ThreadLocal ThreadLocal ThreadLocal ThreadLocal ThreadLocal ThreadLocal

An overview of the

The function of ThreadLocal is mainly for data isolation. The data filled by ThreadLocal only belongs to the current thread. The data of variables is relatively isolated from other threads.

Break down

Can you tell me how it works and in what context

In the source code of Spring to achieve transaction isolation level, Spring uses the method of Threadlocal to ensure that the database operation in a single thread is using the same database connection. At the same time, in this way, the business layer does not need to sense and manage the Connection object when using transactions. Skillfully manage switching, suspending, and resuming between multiple transaction configurations.

Spring framework is used inside the ThreadLocal to achieve this isolation, mainly in TransactionSynchronizationManager this class, the code is as follows:

private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

private static final ThreadLocal<Map<Object, Object>> resources =

new NamedThreadLocal<>(“Transactional resources”);

private static final ThreadLocal<Set> synchronizations =

new NamedThreadLocal<>(“Transaction synchronizations”);

private static final ThreadLocal currentTransactionName =

new NamedThreadLocal<>(“Current transaction name”);

Spring transactions are implemented primarily by ThreadLocal and AOP, but it is important to note that each thread’s own links are maintained by ThreadLocal.

In addition to the scenarios using ThreadLocal in the source code, do you have any scenarios using it yourself? How would you normally use it?

When we went online, we found that some users’ dates were wrong. We found that it was the SimpleDataFormat cooker. At that time, we used SimpleDataFormat’s parse() method and there was a Calendar object inside. The parse() method calling SimpleDataFormat calls calendar.clear () and then calendar.add (). If one thread calls Add () and then another thread calls clear(), The parse() method is at the wrong time.

To solve this problem, it is easy to let each thread new its own SimpleDataFormat, but 1000 threads new1000 SimpleDataFormat?

So we wrapped SimpleDataFormat with a thread pool and ThreadLocal, and then called initialValue to give each thread a copy of SimpleDataFormat, which solved the thread-safety problem and improved performance.

Threads often encounter calls across several methods

I have a thread in the project that often encounters the object that needs to be passed across several method calls, namely the Context, which is a state, usually the user identity, task information, etc., and there will be the problem of over-passing parameters.

Adding a context parameter to each method can be cumbersome using a chain of responsibility pattern, and sometimes object parameters can’t be passed in if the calling chain has a third-party library that can’t modify the source code, so I used ThreadLocal to make a change. You just need to set the parameters in ThreadLocal before the call and get them elsewhere.

I looked at a lot of scenarios where cookie, session and other data isolation is implemented with ThreadLocal.

Underlying implementation principles

ThreadLocal localName = new ThreadLocal();

LocalName. Set (” * * “);

String name = localName.get();

localName.remove();

It’s really easy. The thread comes in and initializes a generic ThreadLocal object, and then whenever the thread gets before remove, it gets the set value.

It can isolate data between threads, so there is no way for another thread to get the value of another thread using get (), but there is a way to do it, as I’ll explain later.

Let’s look at the source of his set:

public void set(T value) {

Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); ThreadLocalMap if (map! Map. set(this, value); Set else createMap(t, value); // Create a map object for nullCopy the code

}

As you can see, the source code for the set is very simple. The main thing to look at is the ThreadLocalMap, which is obtained from a variable called threadLocals for the current Thread.

ThreadLocalMap getMap(Thread t) {

    return t.threadLocals;

}
Copy the code

Each Thread maintains its own threadLocals variable, so when each Thread creates a ThreadLocal, The data is actually stored in the Thread locals variable, which is not available to others.

What does the ThreadLocalMap underlying structure look like

There is a Map that his data structure is actually very similar to HashMap, but you can see the source code, it does not implement Map interface, and its Entry is the inheritance of WeakReference (WeakReference), also do not see next in HashMap, so there is no linked list.

The structure looks something like this:

Why do we need an array? How do you resolve Hash conflicts without linked lists?

We use arrays because we can have multiple TreadLocal for different types of objects on a single thread during development, but they will all be placed in the ThreadLocalMap of your current thread, so you definitely want arrays.

For Hash collisions, let’s take a look at the source code:

ThreadLocalHashCode will be assigned to each ThreadLocal object when it is stored. During the insertion process, the hash value of the ThreadLocal object will be positioned at position I in the table. Int I = key.threadLocalHashCode & (len-1).

If the current position is empty, it initializes an Entry object and places it at position I.

if (k == null) {

replaceStaleEntry(key, value, i);

return;
Copy the code

}

If position I is not empty, and if the key of the Entry object happens to be the key to be set, then the value in the Entry is refreshed;

if (k == key) {

e.value = value;

return;
Copy the code

}

If position I is not empty and key is not equal to entry, the next empty position is found until it is empty.

In this case, during the get, the hash value of the ThreadLocal object will be used to locate the position in the table, and then determine whether the key in the Entry object of this position is the same as the key of the GET. If not, the next position will be determined. If the set and GET conflict seriously, The efficiency is still very low.

Here is the source code for get, does it feel very easy to understand:

Can you tell me where objects are stored

In Java, stack memory is owned by a single thread. Each thread has one stack memory, and the variables it stores are visible only to the thread it belongs to. That is, stack memory can be understood as the thread’s private memory, while objects in heap memory are visible to all threads, and objects in heap memory can be accessed by all threads.

ThreadLocal instances and their values are stored on the stack

It’s not, because ThreadLocal instances are actually held by the class they create (and at the top by the thread), and ThreadLocal values are actually held by the thread instance. They’re all on the heap, but with a trick of making them visible to the thread.

What if I want to share ThreadLocal data for a thread

Use InheritableThreadLocal to create an instance of InheritableThreadLocal that can be accessed by multiple threads. We then get the value set by this InheritableThreadLocal instance in the child thread.

private void test() {

final ThreadLocal threadLocal = new InheritableThreadLocal();

threadLocal.set(“hello”);

Thread t = new Thread() {

@Override public void run() { super.run(); Log.i( "word =" + threadLocal.get()); }}; t.start();Copy the code

}

How is it delivered

The logic for passing is simple. When I mention threadLocals at the beginning of the Thread code, you’ll see that I’ve deliberately added another variable:

Init init init init init init init init init

public class Thread implements Runnable {

if (inheritThreadLocals && parent.inheritableThreadLocals ! = null)

  this.inheritableThreadLocals=ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
Copy the code

}

If the thread’s inheritThreadLocals variable is not empty, as in our example above, and the parent thread’s inheritThreadLocals also exists, So I’m going to give the inheritThreadLocals of the parent thread to the inheritThreadLocals of the current thread.

Memory leaks

That’s going to happen, and I’ll tell you why. Remember my code up here?

When ThreadLocal is saved, it will treat itself as a Key in ThreadLocalMap. Normally, both Key and value should be strongly referenced by the outside world, but now Key is designed as WeakReference.

Let me introduce you to weak references:

Objects with only weak references have a shorter life cycle, and when the garbage collector thread scans the memory area under its control, once it finds an object with only weak references, it reclaims its memory regardless of whether the current memory space is sufficient or not.

However, because the garbage collector is a low-priority thread, objects that have only weak references are not necessarily found quickly.

This leads to the problem that ThreadLocal without strong external references will be reclaimed during GC. If the thread that created the ThreadLocal keeps running, then the value in the Entry object may not be reclaimed and will leak memory.

For example, if a thread in a thread pool is reused, the thread is still alive after the previous thread instance is processed, so the value set by ThreadLocal is held, causing a memory leak.

ThreadLocalMap is supposed to be emptied after a thread is used, but the thread is being reused.

So what’s the solution?

Use remove at the end of the code, just remember to empty the value with remove at the end of the code.

ThreadLocal localName = new ThreadLocal();

try {

LocalName. Set (" * * "); ...Copy the code

} finally {

localName.remove();
Copy the code

}

Remove source code is very simple, find the corresponding value of all empty, so that when the garbage collector to collect, it will automatically reclaim them.

So why are ThreadLocalMap keys designed to be weak references

If the key is not set as a weak reference, the same memory leak scenario occurs as the value in the entry.

One sidebar: I think we can make up for the lack of ThreadLocal by taking a look at Netty’s fastThreadLocal.

ThreadLocal tools

summary

ThreadLocal is pretty simple to use. There are only a few methods in it, and even with the annotated source code, it took me a little more than 10 minutes to go through them, but as I dug into the logic behind each method, I had to marvel at the genius of Josh Bloch and Doug Lea.

In fact, the processing of detail design is often the difference between us and the great god. I think many unreasonable points are found only after the in-depth understanding of Google and myself, which is reasonable. I really refuse to accept it.

ThreadLocal is one of the most popular classes in multithreading. It is not used as often as other methods and classes.