Understanding and use of ThreadLocal

Understanding and use of ThreadLocal

​ When multiple threads access the same shared variable, they are particularly prone to concurrency problems, especially when multiple threads need to write to a shared variable. In order to ensure thread safety, general users need to synchronize appropriately when accessing shared variables.

​ The synchronization measure is generally locking, which requires the user to have a certain understanding of the lock. Therefore, ThreadLocal can be used. When a variable is created, each thread accesses its own variable.

​ ThreadLocal is provided by the JDK package. It provides thread local variables, that is, if you create multiple ThreadLocal variables, each thread accessing this variable will have a local copy of this variable. When multiple threads operate this variable, they actually operate the variables in their own local memory, so as to avoid thread safety problems. After creating a ThreadLocal variable, each thread will copy a variable to its own local memory.

ThreadLocal usage example

/**
 * @author Wenbo
 * @version 1.0
 * @program
 * @description
 * @date 2022/5/24 15:47
 */
public class threadLocalTest {
    static void print(String str){
        System.out.println(str + ":" + localVariable.get());
        localVariable.remove();
    }
    static ThreadLocal<String> localVariable = new ThreadLocal<>();

    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            localVariable.set("Thread variable value of thread 1");
            print("thread1");
            System.out.println("After deleting the variable value of thread 1:" + localVariable.get());
        });

        Thread thread2 = new Thread(()->{
            localVariable.set("Thread variable value of thread 2");
            print("thread2");
            System.out.println("After deleting the variable value of thread 2:" + localVariable.get());
        });
        thread1.start();
        thread2.start();
    }
}
thread1:Thread variable value of thread 1
thread2:Thread variable value of thread 2
 After deleting the variable value of thread 2:null
 After deleting the variable value of thread 1:null

​ The case starts two threads, sets the value of the local variable in each thread, and then calls the print function to print the value of the local variable. When the remove method of the local variable is called after printing, the value of the variable in the local memory will be deleted.

​ In the code, the value of LovalVariable is set through the set method. In fact, a copy in the local memory of thread 1 is set. This copy can only be accessed by thread 1, which can not be accessed by other threads.

Implementation principle of ThreadLocal

​ The details of ThreadLocal implementation are mainly in ThreadLocalMap. One type of Thread class is ThreadLocal ThreadLocalMap's member variable threadLocals, and ThreadLocalMap is a customized Hashmap. By default, the threadLocals variable of each Thread is null. They will be created only when the current Thread calls the set or get method of ThreadLocal for the first time. In fact, the local variables of each Thread are not stored in the ThreadLocal instance, but in the threadLocals variable of the calling Thread. That is, the local variables of ThreadLocal type are stored in the specific Thread memory space. ThreadLocal is a tool shell. It uses the set method to put the value into threadLocals and store it. When the calling Thread calls its get method, it will be used from the threadLocals of the Thread. If the calling Thread does not terminate, the local variable will always be stored in threadLocals of the calling Thread, Therefore, when local variables are not needed, you can use the remove method to manually delete them to avoid memory leakage.

​ Threadlocales in Thread is designed as a map structure, mainly because each Thread can be associated with multiple ThreadLocal variables.

Explanation of set method
/**
	This function is used to get the threadLocals variable of the current thread t, ThreadLocalMap type
*/
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
public void set(T value) {
    // Gets the current thread
    Thread t = Thread.currentThread();
    // Gets the threadLocals variable of the current thread
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value); // If it is not null, set the value to the map. this is the current object (i.e. ThreadLocal object), and value is the variable value passed from the set function
    else
        createMap(t, value); // If map == null, it means that the set method is called for the first time. At this time, the threadLocals variable of the current thread needs to be initialized.
}
/**
 // Initializes threadlocales of the current thread
*/
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
get method explanation
public T get() {
    // Like the set method, get the current thread first
    Thread t = Thread.currentThread();
    // Gets the thread variable of the current thread.
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this); // If the map is not empty, get the value according to the reference of ThreadLocal
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
/**
	ThreadLocalMap From the node form, we can see that it inherits the WeakReference. In fact, the key is not ThreadLocal itself, but a weak reference
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
	// 
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}
Explanation of remove method
/**
	If the thread local variable specified in the current thread is not null, delete it
*/
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}

Summary: there is a member variable named threadlocals inside each thread. The type of the variable is ThreadLocalMap, where key is the this reference of the defined ThreadLocal variable, and value is the value we set using the set method. The local variables of each thread are stored in the thread's own memory variable threadlocals. If the current thread does not die, these local variables will always exist, which may cause memory overflow. Therefore, remember to call the remove method of ThreadLocal to delete the local variables of the corresponding thread after use.

ThreadLocal memory leak

​ The key used in ThreadLocalMap is the weak reference of ThreadLocal. The weak reference is that as soon as the garbage collection mechanism is executed, the memory occupied by the object will be recycled regardless of whether the JVM memory space is sufficient. Therefore, weak references can easily be recycled. If ThreadLocal is recycled by the garbage collector, but the life cycle of ThreadLocalMap is the same as that of Thread. If it is not recycled at this time, the key of ThreadLocalMap will disappear, but the value of value will still be referenced, which will cause memory leakage.

​ To solve the memory leak problem is to use ThreadLocal, even if you call the remove method to free up memory space.

​ The key is also designed as a weak reference to prevent memory leakage. If the key is designed as a strong reference, if the ThreadLocal Reference is destroyed, there will be no strong reference to ThreadLocal. However, if the key is also strongly referenced to ThreadLocal, ThreadLocal cannot be recycled, and memory leakage occurs.

ThreadLocalMap resolves Hash conflicts

​ HashMap uses a linked list to resolve conflicts, which is the so-called chain address method.

​ ThreadLocalMap does not use a linked list. Naturally, it does not use the chain address method to solve conflicts. It uses another method - open addressing method. What does open addressing mean? Simply put, if the pit is occupied, then go on to find the empty pit.

Tags: Interview

Posted by carlmty on Tue, 24 May 2022 17:07:06 +0300