One, foreword
In everyday work, ThreadLocal is often used to avoid thread concurrency problems. Each thread accesses its own local variables, with no contention, no locking, and very efficient. Now we have a business scenario where we need to create child threads to perform tasks. The parent thread sets the value of ThreadLocal and wants to get it from the child thread. Can we get it? The answer is: no.
If the parent thread is a set, then the local map is in the parent thread, and the child thread’s threadLocals is null, how can you get the set from the child thread?
But that’s what the requirement is. How do you implement it? Copy the parent thread’s ThreadLocalMap to the child thread? Yes, Java officials think so too!
Second, the InheritableThreadLocal
1. Method of use
Java uses an InheritableThreadLocal class that uses exactly the same name as a ThreadLocal class. Replace the InheritableThreadLocal with an InheritableThreadLocal and get the value of the parent thread’s set from the child thread.
2. Inheritance
How does InheritableThreadLocal do that? See the real knowledge under the source code:
package java.lang;
/ * * *@author Josh Bloch and Doug Lea
* @see ThreadLocal
* @since1.2 * /
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
InheritableThreadLocal overwrites the methods childValue, getMap, and createMap. InheritableThreadLocals uses the variable inheritableThreadLocals. That’s ThreadLocalMap InheritableThreadLocal initialization assigned to t.i nheritableThreadLocals, set and get is also operating t.i nheritableThreadLocals.
public class Thread implements Runnable {... . ThreadLocal.ThreadLocalMap threadLocals =null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; . . }Copy the code
3. Replication principle
How do you copy the parent thread’s map to the child thread?
To trace Thread initialization, init() is called. Init initializes a lot of things.
InheritThreadLocals =true when creating child threads, the parent thread inheritableThreadLocals =true when creating child threads. =null, the inheritableThreadLocals of the parent thread is copied to the child thread.
// java.lang.ThreadLocal#createInheritedMap
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
Copy the code
//java.lang.ThreadLocal.ThreadLocalMap#ThreadLocalMap
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
// Iterate over the copy
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) {
// InheritableThreadLocal overrides childValue
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
3. What is childValue
In ThreadLocal, childValue is not implemented, and in InheritableThreadLocal, it is simply implemented.
//java.lang.ThreadLocal#childValue
T childValue(T parentValue) {
throw new UnsupportedOperationException();
}
Copy the code
//java.lang.InheritableThreadLocal#childValue
protected T childValue(T parentValue) {
return parentValue;
}
Copy the code
What is the purpose of copying ThreaLocalMap from parent thread to child thread when the value is passed from childValue to Entry? [InheritableThreadLocal] [childValue] [InheritableThreadLocal] [childValue] [childValue] [InheritableThreadLocal] Although InheritableThreadLocal does nothing, users can override childValue by InheritableThreadLocal, doing special processing for the value. Why would you want to do something special for value?
For example, if the value is set to a custom reference type, then the value copied from the parent thread to multiple child threads will have concurrency problems (value passing, address values are shared), so make sure that the address values copied to each child thread are different. InheritableThreadLocal implements a deep copy of the InheritableThreadLocal childValue.
public class MyInheritableThreadLocal<T> extends InheritableThreadLocal<T>{
protected T childValue(T parentValue) {
System.out.println("MyInheritableThreadLocal。。。");
/ / copy
Gson gson = new Gson();
String s = gson.toJson(parentValue);
return(T)gson.fromJson(s, parentValue.getClass()); }}Copy the code
public class InheritableThreadLocalTest {
public static void main(String[] args) throws InterruptedException {
InheritableThreadLocal<Stu> itl = new MyInheritableThreadLocal<Stu>();
itl.set(new Stu());
System.out.println(Parent thread: + itl.get().toString());
Thread thread1 = new Thread(new Runnable() {
@Override
public void run(a) {
System.out.println(Child thread 1:+ itl.get().toString()); }}); thread1.start(); Thread thread2 =new Thread(new Runnable() {
@Override
public void run(a) {
System.out.println(Child thread 2:+ itl.get().toString()); }}); thread2.start(); }static class Stu {
private String name = "xxx"; }}// Console printsParent: com. Stefan. DailyTest. InheritableThreadLocalTest $Stu @49476842MyInheritableThreadLocal... The child thread1: com. Stefan. DailyTest. InheritableThreadLocalTest $Stu @ 7446 b2ac MyInheritableThreadLocal... The child thread2: com. Stefan. DailyTest. F4c190 InheritableThreadLocalTest $Stu @ 75Copy the code
Four,
InheritableThreadLocal
It is possible for a child thread to get a local variable from a parent thread.- Local variable of the parent thread (current thread) when the child thread is initialized
inheritableThreadLocals
If it is not null, it is copied to the child thread. ThreadLocal
Leave achildValue
The idea is to letInheritableThreadLocal
Implementation, and can let the client custom rewritechildValue
Special handling of values copied from parent to child threads.- If used by the parent thread
InheritableThreadLocal
If the value of a custom reference type is set, there is a concurrency problem when copying it to a child threadchildValue
Deep copy of.
Here’s a question:
If a thread pool is used to create a child thread, the child thread is initialized only once, and the parent thread uses InheritableThreadLocal to set the value. Because the replication mechanism is set at thread initialization time, the parent thread can only synchronize the data once when the thread pool initializes the child thread, and the parent thread can modify the value later. Can’t synchronize updates to child threads in the thread pool?
The solution is to use the thread pool and InheritableThreadLocal to create a replication mechanism at every task submission. We have an open source project to provide a solution github.com/alibaba/tra…
PS: If there is any misunderstanding in this article, we welcome your criticism and correction, and look forward to your comments, likes and favorites. I am Xu, willing to make progress with you!
Sky blue and so on misty rain, and I am waiting for you, wechat public number search: Xu students ah, continue to update liver goods, come to pay attention to me, and I study together ~