preface
This article focuses on ThreadLocal, which is rarely used in projects but can be extremely useful. This question is often asked in an interview.
The body of the
This article uses JDK1.8.
ThreadLocal is introduced
Take a look at the introduction of the source code, too many documents, not all posted out
/**
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*
* <p>For example, the class below generates unique identifiers local to each
* thread.
* A thread's id is assigned the first time it invokes {@code ThreadId.get()}
* and remains unchanged on subsequent calls.
Copy the code
use
The usage method is also indicated in the notes:
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
@Override
protected Integer initialValue(a) {
returnnextId.getAndIncrement(); }};// Returns the current thread's unique ID, assigning it if necessary
public static int get(a) {
returnthreadId.get(); }}Copy the code
To summarize:
- ThreadLocal provides a thread-local variable
- Only one variable can be fetched per thread through the set and GET methods of the class
- Initialize variables independently
- The life cycle is the same as the life cycle of a thread
The source code
ThreadLocal
Let’s start with the set method:
public void set(T value) {
// Get the current thread object (so in multi-threaded cases it is the current thread of operation)
Thread t = Thread.currentThread();
// Get ThreadLocalMap from the current thread object
ThreadLocalMap map = getMap(t);
// If ThreadLocalMap is not null, store it directly
if(map ! =null)
// key is the current Threadlocal instance
map.set(this, value);
else
// If ThreadLocalMap is null, a ThreadLocalMap object is created for the current thread
createMap(t, value);
}
Copy the code
Let’s look at the get method:
public T get(a) {
// Get the current thread object
Thread t = Thread.currentThread();
// Get the ThreadLocalMap of the current thread object
ThreadLocalMap map = getMap(t);
if(map ! =null) {
// Get the map Entry object with the current ThreadLocal instance as the key
ThreadLocalMap.Entry e = map.getEntry(this);
if(e ! =null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
returnresult; }}return setInitialValue();
}
Copy the code
Let’s look at the methods used in the above two methods:
- First, the getMap method:
// Multiple methods call this method
ThreadLocalMap getMap(Thread t) {
// Returns the ThreadLocalMap of the incoming thread
return t.threadLocals;
}
Copy the code
- CreateMap method:
void createMap(Thread t, T firstValue) {
// assign value to threadLocals (new)
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
Copy the code
- SetInitialValue method
private T setInitialValue(a) {
// call the initialValue method to get the initialValue
T value = initialValue();
// Get the current thread object
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null)
map.set(this, value);
else
createMap(t, value);
return value;
}
Copy the code
- The initialValue method:
protected T initialValue(a) {
return null;
}
Copy the code
Conclusion 1: Null is returned if the method is not overridden during initialization, so this method will normally override the method in the code that initializes ThreadLocal.
Take a look at the code in Thread:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code
If thread.currentthread () is used to obtain the currentThread object, the set method will operate on the currentThread object. ThreadLocals is a static internal ThreadLocalMap class of the ThreadLocal class, where the key is this (which is the current ThreadLocal instance object).
Summary:
- From the source, the problem of Threadlocal cannot be seen in terms of solving the concurrency problem of multithreaded programs and solving the sharing problem of multithreaded access to resources.
- I am
Threadlocal
The rough understanding is: passThreadlocal
Instance object ofa
To operate the currentThread
In theThreadLocal.ThreadLocalMap
In the objectkey
fora
Corresponding data;
Usage scenarios
1. Database connection pool
The most typical example is the database connection pool. How to handle the relationship between threads and database connections is the use of Threadlocal. For details, go to Google or read the source code.
2. Transfer information or parameters
Here are some of the scenarios I used:
- Information passing Some interfaces do not pass information as parameters, but in such cases you need information that is only available at the beginning, and you can use ThreadLocal to operate.
A memory leak
As for memory leakage, IN fact, I also encountered a memory leak in the process of using; Here’s the scenario:
Here is the flow chart:
We use ThreadLocal to record user information, intercept requests, and store user information, but sometimes in tourist mode, it shows logged in, not your own account.
Why does this happen?
- Request A (with user information A) retrieves thread A from the request connection pool
- The interceptor intercepts thread A and stores A Threadlocal for user information A
- Thread A is then processed in background processing to get user information A from Threadlocal
- After the processing is complete, thread A returns to the connection pool with user information A, Threadlocal’s user information A is not cleared, and thread A is not reclaimed
- Request B (without user information) fetchs thread A from the request connection pool. No user information is retrieved and no operation is performed on Threadlocal
- Go back to Step 2
Solutions:
- Threadlocal is cleared each time at the interceptor (by calling Threadlocal’s remove method)
- Save even if the user information is null;
The last
Blog Address:
GitHub Address:
Java ThreadLocal Java ThreadLocal (ThreadLocal