Introduction to the ThreadLocal class in Java, javathreadlocal
First, we must make it clear that ThreadLocal is not a multi-threaded class, or it should be called a local variable of the thread. This can be seen from the JDK definition of ThreadLocal.
public class ThreadLocal<T>extends Object
It can be seen that ThreadLocal is only an ordinary class and does not inherit from Thread or implement the Runnable interface.
At the same time, we can see that ThreadLocal uses a generic type, so that it can operate on almost any type of data. The following describes the jdk api code.
For this type, see some descriptions in the jdk api:
This class provides thread-local variables. These variables are different from their common counterparts, because each thread accessing a variable (through its get or set method) has its own local variable, which is independent of the initialization copy of the variable. ThreadLocal instances are usually private static fields in the class. They want to associate the state with a thread (such as user ID or transaction ID.
1. ThreadLocal is not a thread, but a local variable in the county.
2. ThreadLocal is usually used as a private static variable in the class.
3. Each thread has its own local variable, which does not conflict with each other. Operations on variable values do not affect each other and there is no resource conflict.
In general, ThreadLocal, as a thread tool, provides a way for each thread to store and access thread variables independently, so that the data stored between different threads does not affect each other (so there is no resource competition problem ).
The following describes how ThreadLocal acts as a thread tool to provide storage and access to local variables of the thread for each thread.
ThreadLocal provides the following APIs for accessing local variables of a thread:
T |
get() Returns the value of the local variable in the current thread copy. |
protected T |
initialValue() Returns the initial value of the current thread for the local variable of this thread. |
void |
remove() Remove the local variable value of this thread. |
void |
set(T value) Set the value in the current thread copy of the local variable of this thread to the specified value. |
You can see that each type is generic. The working principle of the interface is described below.
The ThreadLocal class also provides a static internal class:
Static class ThreadLocalMap
We can regard this ThreadLocalMap as a normal MAP type and save a key-value pair for ease of understanding.
This ThreadLocalMap is defined in ThreadLocal, but is used in the Thread class java. lang. Thread. The Thread class has the following definitions:
ThreadLocal.ThreadLocalMap threadLocals = null
The implication is that the Thread class has a variable similar to the ThreadLocal. ThreadLocalMap type of Map, which can be used to store the value of the key-Value Pair type.
The following is a simple example. The Thread and ThreadLocal processes are analyzed based on the output results.
Class SerialNum
public class SerialNum {// The next serial number to be assigned private static int nextSerialNum = 0; public static ThreadLocal serialNum = new ThreadLocal() { protected synchronized Object initialValue() { return new Integer(nextSerialNum++); } }; public static int get() { return ((Integer) (serialNum.get())).intValue(); } public static void set(int val){ serialNum.set(val); }}
SerialNum class defines a private static ThreadLocal anonymous internal class serialNum variable. In fact, new ThreadLocal can be used directly. In this way, the initialValue method can be rewritten only for the purpose of rewriting, in ThreadLocal, The initialValue () method returns a NULL value. It must be noted that the initialValue () method is a lazy loading method called internally by the ThreadLocal class, it is called only when the get () of the threadLocal class is called for the first time. It is rewritten to give the local variable an initial value.
The static get () and set () Methods of the SerialNum class call the get () and set () Methods of the ThreadLocal class.
Class: ThreadTest
Public class ThreadTest extends Thread {@ Overridepublic void run () {// TODO Auto-generated method stub // print the initial value System first. out. println (Thread. currentThread (). getName () + ":" + SerialNum. get (); // Add 4SerialNum to the current value. set (SerialNum. get () + 4); // print the value System after adding 4. out. println (Thread. currentThread (). getName () + ":" + SerialNum. get ();} public static void main (String [] args) {// TODO Auto-generated method stubThreadTest t = new ThreadTest (); ThreadTest t2 = new ThreadTest (); threadTest t3 = new ThreadTest (); t. start (); t2.start (); t3.start ();}}
The run method in ThreadTest calls the static get () and set () Methods of the SerialNum class.
The output result is as follows:
Thread-2: 2
Thread-0: 0
Thread-1: 1
Thread-2: 6
Thread-0: 4
Thread-1: 5
Next we will analyze why such a result appears. Let's take the Thread-0 as an example. It corresponds to the Thread started by t. start ().
1,When the t thread runs first (thread-0), it will call SerialNum. get (), and it will then call the threadLocal get method. The get () method of ThreadLocal is as follows:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) return (T)map.get(this); // Maps are constructed lazily. if the map for this thread // doesn't exist, create it, with this ThreadLocal and its // initial value as its only entry. T value = initialValue(); createMap(t, value); return value; }
The get () method first obtains the current thread and then calls getMap (). The API method is as follows:
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
GetMap () returns the threadLocals variable in the current Thread. As we have said before, a ThreadLocal. ThreadLocalMap type variable is defined in Thread.
In the get () method, check whether map is not NUll. If it is NULL, initialValue () is called (). This method is overwritten. It returns the current value of the static variable nextSerialNum defined in the SerialNum class, and then adds nextSerialNum + 1. Because nextSerialNum is initially 0, 0 is returned. Then call createMap (t, value ). The API content is as follows:
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
You can see that a ThreadLoadMap object is created in createMap and copied to the threadLocals variable of the current thread. The value of the local variable is saved in the newly created ThreadLocalMap class. The key is this, which is the private static ThreadLocal SerialNum defined in the serialNum class.
Finally, the get () method returns the initialized value 0.
At the same time
The above is the reason why the first output of the thead-0 prints 0.
2,When thread-0 runs to the SerialNum. set (SerialNum. get () + 4); statement, we can see what happened.
First, SerialNum. get () + 4 retrieves the local variable value of the thread saved in the threadLocal variable serialNum. Let's look back at ThreadLocal. get () method introduction, because the current thread already has ThreadLocalMap type threadLocals, so it will directly call map. get (this); where this is still the private static ThreadLocal SerialNum we defined in the serialNum class.
In this way, the value in map is returned. And then call the set () method of ThreadLocal. Let's take a look at the JDK content of the set () method:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
We can see that the set () method first obtains the current thread and obtains the map of threadLocalMap type from the current thread. If map is not null, the value is saved. If it is null, create a new ThreadLocalMap in createMap, save the value, and assign the new threadLocalMap type object to the threadLocals variable of the current thread (see the createMap () method ).
After running, the local variable value is equal to 0 + 4 = 4.
This is why the value printed for the second time is thread-0: 4.
Let's talk about thread-1 in the second thread. When the second thread starts, because the static variable nextSerialNum is already 1 (after being read by thread-0 + ). So he starts printing from 1. The plus 4 operations do not conflict with thread-0 and thread-2. Because:
After the local variable of thread-0 is saved to threadLocalMap, The threadLocalMap variable is copied to the threadLocals variable of the thread (that is, thread-0 itself. Similarly, after the local variables of thread-1 and thread-2 are saved to threadLocalMap, they are all copied to their own threadLocals variables. Therefore, the subsequent operations are to obtain threadLocalMap from the thread. Of course, this will not affect each other. The same is that the keys in threadLocalMap of the three threads are the same ThreadLocal object.
This example shows that after the local variable is initialized, it has nothing to do with the nextSerialNum. This should be described in jdk api:Access a variable (through itsGetOrSetEach thread has its own local variable, which is independent of the initialization copy of the variable.
The above is my own introduction to ThreadLocal. At first, I want to write something straightforward. Later, I felt embarrassed.
For java ThreadLocal Problems
ThreadLocal makes resources shared within the current thread, whether it is cross-package, cross-class, cross-method, this resource can be accessed
The private attribute of the thread class can only be used by other classes in this class.
What is ThreadLocal in java used?
Personally, our software is often layered, such as MVC. Similar to this horizontal hierarchy, ThreadLocal provides a convenient way to provide a storage space within the same thread range, for our use, the vertical storage structure is implemented, so that we can obtain data stored on another layer at any time within the same thread range.