ThreadLocal Details in Multithreading

Keywords: Session Database

To understand ThreadLocal, first find out what ThreadLocal is. What problems are they used to solve?

ThreadLocal is a local variable of a thread, which is held by each thread separately, and cannot be accessed by other threads. It is usually a private static field in the class, which is a copy of the initial value of the field. They want to associate the state with a thread (for example, user ID or transaction ID).

We know that sometimes a variable of an object can be accessed by multiple threads, and there will be thread security problems. Of course, we can use synchorinized keywords to lock and synchronize the variable, so that only one thread can use the variable. But locking will greatly affect the efficiency of program execution. In addition, we can use ThreadLocal to solve the problem. Access conflict for a variable.

When using ThreadLocal to maintain variables, a separate copy of the variable is provided for each thread that uses the variable, that is, there will be one variable within each thread, so that multiple threads can access the variable at the same time without interacting with each other, so they use copies of the variables they copied from memory, so there is no thread safety problem. It will not affect the execution performance of the program.

However, it should be noted that although ThreadLocal can solve the problems mentioned above, because replicas are created in each thread, it is necessary to consider its resource consumption, such as memory usage is larger than that without ThreadLocal.

ThreadLocal method uses elaboration

Several methods of ThreadLocal: ThreadLocal can store any type of variable object, get returns an Object object, but we can use generics to determine the type of storage object.

public T get() { } // To get a copy of the variable saved by ThreadLocal in the current thread
public void set(T value) { } //set() is used to set copies of variables in the current thread
public void remove() { } //remove() is used to remove copies of variables in the current thread
protected T initialValue() { } //initialValue() is a protected method that is generally used for override when used

Thread maintains the ThreadLocal variable table internally through ThreadLocalMap. In the Thread class, there is a threadLocals variable, which is of ThreadLocalMap type. It stores its ThreadLocal variable for each thread. ThreadLocalMap is an internal class of ThreadLocal class. The smallest storage unit in this Map is an Entry, which uses ThreadLocal as its storage unit. For key, variables are value s, because there may be multiple ThreadLocal variables in each thread

Initially, in Thread, threadLocals are empty. When the get() method or set() method is called through the ThreadLocal variable, threadLocals in the Thread class are initialized, and the current ThreadLocal variable is the key value, and the copy variable to be saved by ThreadLocal is the value, which is saved to threadLocals.  
Then in the current thread, if you want to use replica variables, you can find them in threadLocals by get method.

How does ThreadLocal create a copy of a variable for each thread? Here's an example. Examples come from blogs http://www.cnblogs.com/dolphin0520/p/3920407.html

public class ThreadLocalTest {
    public static void main(String[] args) throws InterruptedException {
        final ThreadLocalTest test = new ThreadLocalTest();

        test.set();
        System.out.println(test.getLong());
        System.out.println(test.getString());
        // Here a new thread is created
        Thread thread1 = new Thread() {
            public void run() {
                test.set(); // When the set method is invoked here and the set method of ThreadLocal is further invoked, the ThreadLocal variable is stored in the ThreadLocalMap type member variable threadLocals of the thread. Notice that the threadLocals variable is a variable of the Thread thread, not a variable of the ThreadLocal class.
                System.out.println(test.getLong());
                System.out.println(test.getString());
            };
        };
        thread1.start();
        thread1.join();

        System.out.println(test.getLong());
        System.out.println(test.getString());
    }

    ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
    ThreadLocal<String> stringLocal = new ThreadLocal<String>();

    public void set() {
        longLocal.set(Thread.currentThread().getId());
        stringLocal.set(Thread.currentThread().getName());
    }

    public long getLong() {
        return longLocal.get();
    }

    public String getString() {
        return stringLocal.get();
    }

}
  •  

Output of the code:

main 

Thread-0 

main

ThreadLocal application scenarios

The most common ThreadLocal usage scenario is
Used to solve database connection, Session management, etc.

Database Connection:

Class A implements Runnable{
    private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
        public Connection initialValue() {
                return DriverManager.getConnection(DB_URL);
        }
    };

    public static Connection getConnection() {
           return connectionHolder.get();
    }
}
  •  

Session Management

private static final ThreadLocal threadSession = new ThreadLocal();

public static Session getSession() throws InfrastructureException {
    Session s = (Session) threadSession.get();
    try {
        if (s == null) {
            s = getSessionFactory().openSession();
            threadSession.set(s);
        }
    } catch (HibernateException ex) {
        throw new InfrastructureException(ex);
    }
    return s;
}
  •  

Some of the contents are reproduced from:
http://www.cnblogs.com/dolphin0520/p/3920407.html

Posted by xyzleft on Wed, 15 May 2019 01:54:42 -0700