All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.ttl.TransmittableThreadLocal Maven / Gradle / Ivy

Go to download

a simple lib for transmitting ThreadLocal value between thread even using thread pool.

There is a newer version: 2.5.1
Show newest version
package com.alibaba.ttl;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * {@link TransmittableThreadLocal} can transmit value from the thread of submitting task to the thread of executing task.
 * 

* Note: this class extends {@link java.lang.InheritableThreadLocal}, * so {@link TransmittableThreadLocal} first is a {@link java.lang.InheritableThreadLocal}. * * @author Jerry Lee (oldratlee at gmail dot com) * @see TtlRunnable * @see TtlCallable * @since 0.10.0 */ public class TransmittableThreadLocal extends InheritableThreadLocal { /** * Computes the value for this transmittable thread-local variable * as a function of the source thread's value at the time the task * Object is created. This method is called from {@link TtlRunnable} or * {@link TtlCallable} when it create, before the task is started. *

* This method merely returns reference of its source thread value, and should be overridden * if a different behavior is desired. * * @since 1.0.0 */ protected T copy(T parentValue) { return parentValue; } /** * Callback method before task object({@link TtlRunnable}/{@link TtlCallable}) execute. *

* Default behavior is do nothing, and should be overridden * if a different behavior is desired. *

* Do not throw any exception, just ignored. * * @since 1.2.0 */ protected void beforeExecute() { } /** * Callback method after task object({@link TtlRunnable}/{@link TtlCallable}) execute. *

* Default behavior is do nothing, and should be overridden * if a different behavior is desired. *

* Do not throw any exception, just ignored. * * @since 1.2.0 */ protected void afterExecute() { } @Override public final T get() { T value = super.get(); if (null != value) { addValue(); } return value; } @Override public final void set(T value) { super.set(value); if (null == value) { // may set null to remove value removeValue(); } else { addValue(); } } @Override public final void remove() { removeValue(); super.remove(); } private void superRemove() { super.remove(); } T copyValue() { return copy(get()); } static ThreadLocal, ?>> holder = new ThreadLocal, ?>>() { @Override protected Map, ?> initialValue() { return new WeakHashMap, Object>(); } }; void addValue() { if (!holder.get().containsKey(this)) { holder.get().put(this, null); // WeakHashMap supports null value. } } void removeValue() { holder.get().remove(this); } static Map, Object> copy() { Map, Object> copy = new HashMap, Object>(); for (TransmittableThreadLocal threadLocal : holder.get().keySet()) { copy.put(threadLocal, threadLocal.copyValue()); } return copy; } static Map, Object> backupAndSet(Map, Object> copied) { Map, Object> backup = new HashMap, Object>(); for (Iterator, ?>> iterator = holder.get().entrySet().iterator(); iterator.hasNext(); ) { Map.Entry, ?> next = iterator.next(); TransmittableThreadLocal threadLocal = next.getKey(); // backup backup.put(threadLocal, threadLocal.get()); // clean extra TTL value in destination thread if (!copied.containsKey(threadLocal)) { iterator.remove(); threadLocal.superRemove(); } } // set new TTL value for (Map.Entry, Object> entry : copied.entrySet()) { @SuppressWarnings("unchecked") TransmittableThreadLocal threadLocal = (TransmittableThreadLocal) entry.getKey(); threadLocal.set(entry.getValue()); } // call beforeExecute callback doExecuteCallback(true); return backup; } static void restore(Map, Object> backup) { // call afterExecute callback doExecuteCallback(false); for (Iterator, ?>> iterator = holder.get().entrySet().iterator(); iterator.hasNext(); ) { Map.Entry, ?> next = iterator.next(); TransmittableThreadLocal threadLocal = next.getKey(); // clean extra TTL value if (!backup.containsKey(threadLocal)) { iterator.remove(); threadLocal.superRemove(); } } // restore TTL value for (Map.Entry, Object> entry : backup.entrySet()) { @SuppressWarnings("unchecked") TransmittableThreadLocal threadLocal = (TransmittableThreadLocal) entry.getKey(); threadLocal.set(entry.getValue()); } } private static void doExecuteCallback(boolean isBefore) { for (Map.Entry, ?> entry : holder.get().entrySet()) { TransmittableThreadLocal threadLocal = entry.getKey(); try { if (isBefore) { threadLocal.beforeExecute(); } else { threadLocal.afterExecute(); } } catch (Throwable t) { t.printStackTrace(); } } } }