[InheritableThreadLocal] [InheritableThreadLocal] [InheritableThreadLocal]
A Thread constructor calls only one init method, which takes the Boolean inheritThreadLocals parameter to indicate whether the child inherits the parent Thread’s threadLocal. For most Thread constructors, this argument is true.
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals)
Copy the code
The body of the function:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager what to do. */
if(security ! =null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter use the parent thread group. */
if (g == null) { g = parent.getThreadGroup(); }}/* checkAccess regardless of whether or not threadgroup is explicitly passed in. */
g.checkAccess();
/* * Do we have the required permissions? * /
if(security ! =null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = acc ! =null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if(inheritThreadLocals && parent.inheritableThreadLocals ! =null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
Copy the code
If the inheritableThreadLocals of the parent thread is not empty, execute:
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
Copy the code
So continue with the source code:
Enclosing inheritableThreadLocals is a member variable of the Thread, type of ThreadLocal. ThreadLocalMap:
/* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
Copy the code
ThreadLocal createInheritedMap method:
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
Copy the code
Then with:
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if(e ! =null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if(key ! =null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while(table[h] ! =null) h = nextIndex(h, len); table[h] = c; size++; }}}}Copy the code
In the constructor above, we see that the Entry[] array of ThreadLocalMap is reconstructed, but the key in each Entry is the same as the threadLocal in the parent thread, and the value is called
T parentValue (), and the InheritableThreadLocal class returns the same value in the parent thread by default. So if you want to clear a value, you need to call clear on both InheritableThreadLocal and parent threads.
T childValue (T parentValue) implementation in TreadLocal throws an exception, so the thread of ThreadLocal. ThreadLocalMap inheritableThreadLocals variables, The key in the Entry points to an InheritableThreadLocal.
To sum up
We see that if the parent thread
ThreadLocal. ThreadLocalMap inheritableThreadLocals variable, if not null, Can copy out a ThreadLocal. ThreadLocalMap object is assigned to the child thread inheritableThreadLocals variables. And the key in the Entry for inheritableThreadLocals points to InheritableThreadLocal.
[InheritableThreadLocal] [T parentValue] [T parentValue] [InheritableThreadLocal] [T parentValue] [T parentValue]
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); }}Copy the code
I already followed the childValue method, so let’s go ahead
ThreadLocalMap getMap(Thread t) and void createMap(Thread t, t firstValue); To the first
CreateMap (Thread t, t firstValue); ThreadLocal#public void set(T value); ThreadLocal#private T setInitialValue();
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null)
map.set(this, value);
else
createMap(t, value);
}
Copy the code
When InheritableThreadLocal calls public void set(T value)
The getMap (t) is invoked InheritableThreadLocal covering method Returns the t.i nheritableThreadLocals; Then, if the map is null, createMap(t, value) is called; Call the override method in InheritableThreadLocal, which assigns a ThreadLocalMap to the thread’s inheritableThreadLocals variable.
private T setInitialValue(a) {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null)
map.set(this, value);
else
createMap(t, value);
return value;
}
Copy the code
As mentioned above, this code is basically the same as the public void set(T value) method, so I won’t analyze it here.
With:
ThreadLocalMap getMap(Thread t) where the rest of the Thread is used:
public T get(a) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if(e ! =null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
returnresult; }}return setInitialValue();
}
public void remove(a) {
ThreadLocalMap m = getMap(Thread.currentThread());
if(m ! =null)
m.remove(this);
}
Copy the code
As above, the simplicity is not elaborated.
Now we’re done with the source code for InheritableThreadLocal
Finally, to sum up:
If we use InheritableThreadLocal to create a threadLocal, then the InheritableThreadLocal will be stored in the thread
InheritableThreadLocals variable, and when you are new to a thread, the parent thread ThreadLocal. The ThreadLocalMap inheritableThreadLocals variable, if not null, Can copy out a ThreadLocal. ThreadLocalMap object is assigned to the child thread inheritableThreadLocals variables.