I. Overview
What is ThreadLocal? In fact, ThreadLocal is not a local implementation version of a thread. It is not a Thread, but a threadlocal variable (thread local variable). Maybe it would be more appropriate to name it ThreadLocalVar. The actual function of thread local variables (ThreadLocal) is very simple. It is to provide a copy of the variable value for each thread that uses the variable. It is a special thread binding mechanism in Java that allows each thread to independently Change your own copy without conflicting with other threads' copies.
From a thread's perspective, each thread maintains an implicit reference to its copy of a thread-local variable as long as the thread is active and the ThreadLocal instance is accessible; after the thread disappears, all copies of its thread-local instance will be Garbage collection (unless there are other references to these copies).
Data accessed through ThreadLocal is always related to the current thread. That is to say, the JVM binds a private local instance access space to each running thread, thus providing a solution for concurrent access problems that often occur in multi-threaded environments. An isolation mechanism.
How does ThreadLocal maintain a copy of variables for each thread? In fact, the implementation idea is very simple. There is a Map in the ThreadLocal class, which is used to store a copy of the variables of each thread.
To sum up, for the problem of multi-thread resource sharing, the synchronization mechanism adopts the method of "exchanging time for space", while ThreadLocal adopts the method of "exchanging space for time". The former only provides a copy of the variable for different threads to queue for access, while the latter provides a copy of the variable for each thread, so it can be accessed at the same time without affecting each other.
2. API Description
ThreadLocal()
Create a thread local variable.
T get()
Returns the value in the current thread's copy of this thread-local variable, which is created and initialized if this is the first time the thread calls this method.
protected T initialValue()
Returns the current thread's initial value for this thread-local variable. This method is called at most once per thread access to obtain each thread-local variable, that is, when the thread first accesses the variable using the get() method. If the thread calls the set(T) method before the get method, the initialValue method will not be called again in the thread.
If this implementation simply returns null; if the programmer wishes to initialize thread-local variables to a value other than null, the programmer must subclass ThreadLocal and override this method. Typically, anonymous inner classes will be used. A typical implementation of initialValue will call an appropriate constructor and return the newly constructed object.
void remove()
Removes the value of this thread-local variable. This may help reduce storage requirements for thread-local variables. If this thread-local variable is accessed again, it will have its initialValue by default.
void set(T value)
Sets the value in the current thread's copy of this thread-local variable to the specified value. Many applications do not require this functionality and rely only on the initialValue() method to set the value of thread-local variables.
In programs, the initialValue method is generally overridden to give a specific initial value.
3. Typical examples
1. Hiberante’s Session tool class HibernateUtil
This class is the HibernateUtil class in Hibernate's official documentation and is used for session management.
public class HibernateUtil {
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static final SessionFactory sessionFactory; //Define SessionFactory
static {
try {
//Create SessionFactory
through the default configuration file hibernate.cfg.xml sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
log.error("Initialization of SessionFactory failed!", ex);
throw new ExceptionInInitializerError(ex);
}
}
//Create thread local variable session to save Hibernate's Session
public static final ThreadLocal session = new ThreadLocal();
/**
* Get the Session
in the current thread * @return Session
* @throws HibernateException
*/
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// If the Session is not open yet, open a new Session
if (s == null) {
s = sessionFactory.openSession();
session.set(s); //Save the newly opened Session into thread local variables
}
return s;
}
public static void closeSession() throws HibernateException {
//Get thread local variables and cast to Session type
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
In this class, since the initialValue() method of ThreadLocal is not overridden, the thread local variable session is created for the first time and its initial value is null. When currentSession() is called for the first time, the get() method of the thread local variable is also null. . Therefore, the session is judged. If it is null, a new Session is opened and saved in the thread local variable session. This step is very critical. This is also the object created by "public static final ThreadLocal session = new ThreadLocal()" The reason why session can be coerced into a Hibernate Session object.
2. Another example
Create a Bean and set the Bean properties through different thread objects to ensure the independence of each thread Bean object.
/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-11-23
* Time: 10:45:02
* 学生
*/
public class Student {
private int age = 0; //Age
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-11-23
* Time: 10:53:33
* Test program under multi-threading
*/
public class ThreadLocalDemo implements Runnable {
//Create the thread local variable studentLocal, which you will find later to save the Student object
private final static ThreadLocal studentLocal = new ThreadLocal();
public static void main(String[] agrs) {
ThreadLocalDemo td = new ThreadLocalDemo();
Thread t1 = new Thread(td, "a");
Thread t2 = new Thread(td, "b");
t1.start();
t2.start();
}
public void run() {
accessStudent();
}
/**
* Sample business method for testing
*/
public void accessStudent() {
//Get the name of the current thread
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName " is running!");
//Generate a random number and print
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " currentThreadName " set age to:" age);
//Get a Student object and insert the random age into the object attribute
Student student = getStudent();
student.setAge(age);
System.out.println("thread " currentThreadName " first read age is:" student.getAge());
try {
Thread.sleep(500);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("thread " currentThreadName " second read age is:" student.getAge());
}
protected Student getStudent() {
//Get local thread variables and cast them to Student type
Student student = (Student) studentLocal.get();
//When the thread executes this method for the first time, studentLocal.get() must be null
if (student == null) {
//Create a Student object and save it to the local thread variable studentLocal
student = new Student();
studentLocal.set(student);
}
return student;
}
}
operation result:
a is running!
thread a set age to:76
b is running!
thread b set age to:27
thread a first read age is:76
thread b first read age is:27
thread a second read age is:76
thread b second read age is:27
It can be seen that the values printed by the two threads age at different times are exactly the same. This program uses ThreadLocal to achieve multi-thread concurrency while taking into account data security.
4. Summary
ThreadLocal is used mainly to solve the problem of data inconsistency due to concurrency in multi-threads. ThreadLocal provides a copy of the data that is accessed concurrently in each thread, and runs the business by accessing the copy. This consumes memory, greatly reduces the performance consumption caused by thread synchronization, and also reduces the complexity of thread concurrency control. Spend.
ThreadLocal cannot use atomic types, only Object types. The use of ThreadLocal is much simpler than synchronized.
Both ThreadLocal and Synchonized are used to solve multi-threaded concurrent access. But there is an essential difference between ThreadLocal and synchronized. Synchronized uses a lock mechanism so that a variable or code block can only be accessed by one thread at a time. ThreadLocal provides a copy of the variable for each thread, so that each thread does not access the same object at a certain time, thus isolating the data sharing of data by multiple threads. Synchronized is just the opposite. It is used to obtain data sharing when communicating between multiple threads.
Synchronized is used for data sharing between threads, while ThreadLocal is used for data isolation between threads.
Of course, ThreadLocal cannot replace synchronized, they deal with different problem domains. Synchronized is used to implement synchronization mechanism and is more complex than ThreadLocal.
5. General steps for using ThreadLocal
1. In a multi-threaded class (such as the ThreadDemo class), create a ThreadLocal object threadXxx to save the object xxx that needs to be isolated between threads.
2. In the ThreadDemo class, create a method getXxx() to obtain the data to be accessed in isolation. Judge in the method that if the ThreadLocal object is null, you should new() an object of the isolation access type and force it to be applied. type.
3. In the run() method of the ThreadDemo class, obtain the data to be operated through the getXxx() method. This ensures that each thread corresponds to a data object, and this object is operated at any time.
The above is the detailed content of How to use the java.lang.ThreadLocal class. For more information, please follow other related articles on the PHP Chinese website!