Step 1: Analyze the source code of ThreadLocal
ThreadLocal has an inner class ThreadLocalMap, the implementation of this class accounts for more than half of the source code of the entire ThreadLocal class. The role of this ThreadLocalMap is very critical, it is the container where the thread really saves the thread's own local variables. Each thread has its own separate instance of ThreadLocalMap,
public T get() { //Get the current thread of execution Thread t = Thread.currentThread(); //Get the ThreadLocalMap instance of the current thread ThreadLocalMap map = getMap(t); //If the map is not empty, it means that the thread already has a ThreadLocalMap instance if (map != null) { //map saves all thread local variables of the thread, we are going to find the current thread local variable ThreadLocalMap.Entry e = map.getEntry(this); //If the current thread local variable exists in this map, return its corresponding value if (e != null) return (T)e.value; } //If the map does not exist or the current thread local variable does not exist in the map, return the initial value return setInitialValue(); }
Note that the last step here is to call
InitialValue() method to initialize local variablesThe Thread object has an attribute threadLocals of type ThreadLocalMap, which is specially used to save all its own thread local variables. This property is null when the thread object is initialized. Therefore, when using a thread local variable for the first time for a thread object, you need to initialize the threadLocals property.
getMap method: //Return directly to the threadLocals property of the thread object ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
setInitialValue method: private T setInitialValue() { //Get the initialization value, initialValue is the method we covered before T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); //If the map is not empty, put the initialization value into the ThreadLocalMap object of the current thread if (map != null) map.set(this, value); else //The first time the current thread uses the local thread variable, the map needs to be initialized createMap(t, value); //return the initial value return value; }
Let's look at the set method again public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); // Explain that the thread uses the thread local variable for the first time (note the first meaning here) else createMap(t, value); } ThradLocal also has a remove method: public void remove() { //Get the ThreadLocalMap object of the current thread ThreadLocalMap m = getMap(Thread.currentThread()); //If the map is not empty, delete the value of the local variable if (m != null) m.remove(this); }
Step 2: Application Analysis
package com.threadlocal; import java.util.logging.Logger; public class threadlocaldemo { private static Logger logger =Logger.getLogger("threadlocaldemo.class"); private static int id=0; private static ThreadLocal<People> threadLocal =new ThreadLocal<People>() { protected People initialValue() { People people =new People(); people.setId(++id); return people; }; }; public static void main(String[] args) { logger.info("Test started"); for(int i=0;i<5;i++) { new Thread(new Runnable() { public void run() { System.out.println("my name is :"+Thread.currentThread().getName()+"--"+threadLocal.get().getId()); }; }).start(); } } }result:
May 03, 2018 10:55:15 am com.threadlocal.threadlocaldemo main INFO: Test started my name is :Thread-3--3 my name is :Thread-5--2 my name is :Thread-4--1 my name is :Thread-2--1 my name is :Thread-1--1
From the results, it can be clearly seen that the effect of mutual isolation of variables between threads is not achieved.
private static int id=0; private static ThreadLocal<People> threadLocal =new ThreadLocal<People>() { protected People initialValue() { People people =new People(); people.setId(++id); return people; }; };
model in this case
Case two: package com.threadlocal; import java.util.logging.Logger; public class threadlocaldemo { private static Logger logger =Logger.getLogger("threadlocaldemo.class"); private static ThreadLocal<People> threadLocal =new ThreadLocal<People>() { protected People initialValue() { int id=0; People people =new People(); people.setId(++id); return people; }; }; public static void main(String[] args) { logger.info("Test started"); for(int i=0;i<5;i++) { new Thread(new Runnable() { public void run() { System.out.println("my name is :"+Thread.currentThread().getName()+"--"+threadLocal.get().getId()); }; }).start(); } } }
result:
INFO: Test started my name is :Thread-5--1 my name is :Thread-1--1 my name is :Thread-3--1 my name is :Thread-4--1 my name is :Thread-2--1
Model: