We know that spring has reduced the difficulty of developers using a variety of data persistence technologies through a variety of template classes. These template classes are thread-safe, meaning that multiple DAO can reuse the same template instance without conflicts. We use the template class to access the underlying data, and depending on the persistence technology, the template class needs to bind the resources of the data connection or session. However, these resources are inherently non-thread-safe, meaning that they cannot be shared by multiple threads at the same time. Although the template class obtains a data connection or session through a resource pool, the resource pool itself addresses the caching of data connections or sessions and is not a thread-safe issue for data connections or sessions.
In the traditional experience, if an object is non-thread-safe, access to the object must be thread-synchronized with synchronized in a multithreaded environment. However, the template class does not adopt the thread synchronization mechanism because thread synchronization reduces concurrency and affects system performance. In addition, the challenge of addressing thread safety through code synchronization can be much more difficult to implement several times. So what kind of magic can a template class rely on to resolve thread-safety problems without thread synchronization? The answer is threadlocal!.
Threadlocal play an important role in spring, in the management of the request scope of the bean, transaction management, task scheduling, AOP and other modules have appeared their figure, play a pivotal role. To understand the underlying technology of spring transaction management, Threadlocal is the fortress of the hill that must be conquered.
1 threadlocal Overview
As early as the version of JDK 1.2, Java.lang.threadlocal,threadlocal provides a new way to solve the concurrency problem of multi-threaded threads. Using this tool class, you can write beautiful multithreaded programs very concisely.
ThreadLocal, as the name implies, is not a thread, but a localized object of a thread. When an object working in multi-threading uses threadlocal to maintain a variable, threadlocal assigns a separate copy of the variable to each thread that uses the variable. So each thread can change its own copy independently, without affecting the copy of the other thread. from the thread's point of view, this variable is like a thread's local variable, which is the meaning of the "local" in the class name.
Thread-local variables are not a new Java invention, and many languages (such as IBM XL, FORTRAN) provide thread-local variables at the syntactic level. Language-level support is not available in Java, and support is provided through threadlocal classes in a workaround. Therefore, the code to write thread-local variables in Java is relatively awkward, which is why thread-local variables are not well-developed among Java developers.
To learn the classes in the JDK, first look at the JDK API's description of this class, described below:
This class provides thread-local (thread-local) variables. These variables are different from their ordinary counterparts, because each thread that accesses a variable (through its Get or set method) has its own local variable, independent of the initialized copy of the variable. ThreadLocal instances are typically private static fields in a class that want to associate the state with a thread (for example, a user ID or transaction ID).
The API expresses the following views:
- Threadlocal is not a thread, it is a variable of a thread, and you can simply understand the attribute variables of the thread class.
- Threadlocal are typically defined as static variables in a class.
- Each thread has its own threadlocal, which is a "copy" of the variable, and modifying it does not affect other threads.
Since it is defined as a class variable, why maintain a copy for each thread (called "Copy" is easy to understand), so that each thread can be accessed independently? The experience of multithreaded programming tells us that for threads to share resources (which you can understand as attributes), whether the resource is shared by all threads, that is, if the resource is modified by one thread to affect the run of another thread, and if it affects our need to use synchronized synchronization, let the thread sequentially access it.
Threadlocal is suitable for resource sharing but does not need to maintain the state of the situation, that is, one thread changes the resources, does not affect the operation of another thread, this design is ' space for time ', synchronized sequential execution is ' time for space '.
2 threadlocal methods and examples of use
The Threadlocal class plays a very important role in the framework of spring,hibernate and so on. To explain how the Threadlocal class works, you must also introduce several other classes that work well with them, including the inner class Threadlocalmap, and thread class threads.
The four core methods are described below:
T |
Get () Returns the value in the current thread copy of this thread's local variable. |
Protected T |
InitialValue () Returns the "initial value" of the current thread for this thread's local variables. |
void |
Remove () Removes the value of the current thread for this thread's local variables. |
void |
Set (T value) Sets the value in the current thread copy of this thread's local variable to the specified value. |
Some people may think that thread has something to do with threadlocal, but the real mystery is a line of code in the thread class:
Threadlocal.threadlocalmap threadlocals = null;
Where Threadlocalmap is defined in the Threadlocal class, the real reference is in the thread class. So what exactly is Threadlocalmap? You can see that this class is supposed to be a map,jdk explanation:Threadlocalmap is a customized hash map suitable single for maintaining thread local values.
The next focus is on the entry used to store the data in Threadlocalmap:
Static Class Entry extends Weakreference<threadlocal> {/** The value associated with this threadlocal. */object valu E Entry (ThreadLocal K, Object v) {super (k); value = V;}} </threadlocal>
From which we can find that the key of this map is the threadlocal variable, value is the user values, not many people think that key is the name or identity of the thread. Here, we can understand how threadlocal really works.
- The thread class has a member variable called Threadlocalmap, which is a map, and his key is the Threadlocal class
- Each thread has its own declared variable of type threadlocal, so the name of this class is called Threadlocal: Thread's Own (variable).
- This variable life cycle is determined by the thread, starting at the first initialization (get or Set method).
- This is determined by how threadlocal works: Each thread has a variable, not a share or a copy, on its own.
Below, we have a specific example to understand the specific use of threadlocal.
public class SequenceNumber {//① threadlocal () method overrides InitialValue by anonymous inner class, specifying the initial value of private static threadlocal<integer> SeqNum = new threadlocal<integer> () {public integer initialvalue () {return 0;}};/ /② gets the next sequence value public int getnextnum () {Seqnum.set (Seqnum.get () + 1); return Seqnum.get ();} public static void Main (string[] args) {sequencenumber sn = new SequenceNumber ();//③3 threads share sn, each generating serial number testclient T1 = new T Estclient (SN); TestClient t2 = new TestClient (SN); testclient t3 = new TestClient (SN); T1.start (); T2.start (); T3.start ();} private static class TestClient extends Thread {private SequenceNumber sn;public testclient (sequencenumber sn) {this.sn = SN;} public void Run () {//④ 3 sequence values per thread for (int i = 0; i < 3; i++) {System.out.println ("thread[" + thread.currentthread (). Get Name () + "] sn[" + sn.getnextnum () + "]");}}} </integer></integer>
Usually we define the subclass of threadlocal by means of an anonymous inner class, providing the initial value of the variable, as shown in ①. TestClient threads produce a set of serial numbers, and at ③ we generate 3 testclient that share the same SequenceNumber instance. Run the above code and output the following results on the console:
Thread[thread-2] sn[1]thread[thread-0] sn[1]thread[thread-1] sn[1]thread[thread-2] sn[2]thread[Thread-0] sn[2] THREAD[THREAD-1] sn[2]thread[thread-2] sn[3]thread[thread-0] sn[3]thread[thread-1] sn[3]
Examining the result information of the output, we find that each thread produces an ordinal number that shares the same sequence number instance, but they do not interfere with each other, but instead produce separate serial numbers. This is because we provide a separate copy of each thread through threadlocal.
Next analysis of Threadlocal source code, it is more clear.
3 in-depth source
Threadlocal has a threadlocalmap static inner class that you can simply understand as a map, which copies a variable's ' copy ' of each thread to store it.
When a thread calls the Threadlocal.get () method to get a variable, it first gets the current thread reference, which is the key to get the threadlocalmap of the response, and if this ' Map ' does not exist initialize one, otherwise return the variable, the code is as follows:
Public T get () {Thread T = Thread.CurrentThread ();/** * Gets the threadlocalmap of the current thread */threadlocalmap map = Getmap (T); if (map! = null) {/** * Threadlocalmap in this thread looks for key for the current Threadlocal object Entry */threadlocalmap.entry e = Map.getentry (this); if (E! = null) return (T) E.value;} return Setinitialvalue ();}
/** * Key method that returns the current thread's threadlocalmap * [[[Each thread returns to its respective threadlocalmap, so the threadlocal in the individual threads is independent]] */ Threadlocalmap Getmap (Thread t) {return t.threadlocals;}
Call the Get method if this map does not exist first initialize, create this map, place the thread as key, initialize the Vlaue into it, note here the InitialValue, we can override this method, initialize an appropriate value on the first call.
For threadlocal to store a copy of the variable, we look at the Getmap method: Gets the Threadlocals property of the current thread's threadlocal type. obviously a copy of the variable is stored in each thread.
The Setinitialvalue code is as follows:
Private T Setinitialvalue () {/** * returns null by default, this method is protected can inherit */t value = InitialValue (); Thread t = Thread.CurrentThread (); Threadlocalmap map = getmap (t), if (map! = null) Map.set (this, value); else/** * Initial creation of */createmap (t, value); return Value;}
/** * gives the current Thread the initial threadlocalmap */void createmap (Thread T, T firstvalue) {t.threadlocals = new Threadlocalmap ( this, firstvalue);}
The set method is relatively simple, if you understand both methods. Gets a reference to the current thread, gets the map of the thread from the map, and if the map has an updated cache value, it is created and stored with the following code:
public void Set (T value) {Thread T = Thread.CurrentThread (); Threadlocalmap map = getmap (t), if (map! = null) Map.set (this, value); Elsecreatemap (T, value);}
Above we know where the copy of the variable is stored, here we simply say how to be collected by the Java garbage collection mechanism, when we do not use the call set (NULL), at this point, the reference to the ' Map ', and when a thread exits, it performs a resource reclamation operation that reclaims the requested resource, essentially setting the property's reference to null. There is no reference to the map at this point and it is garbage collected.
We can implement a simplified version of Threadlocal, which has a map that stores a variable copy of each thread, the key of the element in the map is the thread object, and the value corresponds to the variable copy of the thread.
public class Simplethreadlocal {private Map ValueMap = Collections.synchronizedmap (New HashMap ());p ublic void Set (Object NewValue) {//① key is a thread object, the value is a variable copy of this thread Valuemap.put (Thread.CurrentThread (), newvalue);} public object Get () {Thread CurrentThread = Thread.CurrentThread ();//② returns the variable corresponding to this thread Object o = Valuemap.get (CurrentThread) //③ If it does not exist in map, put it in map to save if (o = = null &&!valuemap.containskey (CurrentThread)) {o = InitialValue (); Valuemap.put (CurrentThread, O);} return o;} public void Remove () {Valuemap.remove (Thread.CurrentThread ());} Public Object InitialValue () {return null;}}
Although this threadlocal implementation version of the code listing above appears naïve, it is very similar to the Threadlocal class provided by the JDK in its implementation.
Through the above analysis, we found that the use of threadlocal class is used to solve the problem of multithreading, but still has a very clear pertinence. Most obviously, the THREADLOACL variable is scoped to a thread, and my understanding is that the thread is "proprietary, hogging", and all operations on that variable are done by that thread! In other words,threadlocal is not used to solve the problem of sharing, competition . A typical application is the processing of multithreading in a framework such as spring,hibernate.
The following are the typical threadlocal applications in hibernate:
private static final ThreadLocal threadsession = new ThreadLocal ();p ublic static Session getsession () throws Infrastructur Eexception {Session S = (session) Threadsession.get (); try {if (s = = null) {s = Getsessionfactory (). Opensession (); threadses Sion.set (s);}} catch (Hibernateexception ex) {throw new Infrastructureexception (ex);} return s;}
This code, each thread has its own threadlocalmap, each threadlocalmap in accordance with the need to initially load threadsession, the benefit is between Singleton and prototype, Application singleton can not solve the thread, the application prototype overhead is too large, with the threadlocal after the good, for the thread "occupy" the variable with threadlocal, and the method of the class instance can be shared.
About memory leaks: Although Threadlocalmap has already used weakreference, it is recommended to use the Remove method for display.
4 comparison with thread synchronization mechanism
What are the advantages of threadlocal compared to the thread synchronization mechanism? Both the threadlocal and thread synchronization mechanisms are designed to address the access violation of the same variable in multiple threads.
In the synchronization mechanism, the lock mechanism of the object guarantees that only one thread accesses the variable at the same time. At this time the variable is shared by multiple threads, using the synchronization mechanism requires the program to carefully analyze when to read and write variables, when to lock an object, when to release object locks and other complex problems, programming and writing is relatively difficult.
Threadlocal, however, solves multiple threads of concurrent access from another angle. Threadlocal provides a separate copy of the variable for each thread, isolating multiple threads from conflicting access data. Because each thread has its own copy of the variable, there is no need to synchronize the variable. Threadlocal provides a thread-safe object encapsulation that can encapsulate unsafe variables into threadlocal when writing multithreaded code.
Because the threadlocal can hold any type of object, the Get () provided by the lower version of the JDK returns an object, which requires a type cast. However, JDK 5.0 is a good solution to this problem through generics, to some extent simplifying the use of threadlocal, code listing 9-2 uses the JDK 5.0 new threadlocal version.
To sum up, for multi-threaded resource sharing problem, the synchronization mechanism adopted the "time-to-space" approach: Access serialization, object sharing. The threadlocal uses the "space-for-time" approach: Access parallelization, and the exclusive use of objects. The former provides only one copy of the variable, allowing different threads to queue access, and the latter provides a variable for each thread, so it can be accessed at the same time without affecting each other.
5 Spring uses threadlocal to resolve thread safety issues
We know that in general, only stateless beans can be shared in a multithreaded environment, and in spring, most beans can be declared as singleton scopes. This is because spring has a "stateful object" of non-thread safety for some beans (such as Requestcontextholder, Transactionsynchronizationmanager, Localecontextholder, etc.) Encapsulation with threadlocal makes them also "stateful objects" that are thread-safe, so stateful beans can work in a singleton manner in multi-threading.
the general Web application divides into the presentation layer, the service layer and the persistence layer three levels, writes the corresponding logic in the different layers, the lower layer through the interface to the upper layer open function calls. in general, all program calls from receiving requests to returning responses belong to one thread, as shown in 9-2.
This allows the user to store some non-thread-safe variables in threadlocal as needed, and the same threadlocal variable accessed by all objects in the same invocation thread of the same request response is bound by the current thread.
The following example can reflect spring's transformation of the stateful bean:
Topicdao: Non-thread safe
public class Topicdao {//① a non-thread-safe variable private Connection conn;public void Addtopic () {//② refers to a non-thread-safe variable statement stat = Conn.cre Atestatement ();//...}}
Because the conn at ① is a member variable, because the Addtopic () method is non-thread-safe, a new Topicdao instance (not singleton) must be created when it is used. the following uses threadlocal to transform Conn, a non-thread-safe "state":
Topicdao: Thread Safety
Import Java.sql.connection;import Java.sql.statement;public class Topicdao {//① use threadlocal to save Connection variable private static threadlocal<connection> connthreadlocal = new threadlocal<connection> ();p ublic static connection Getconnection () {//② If connthreadlocal does not have a connection corresponding to this thread to create a new connection,//and save it to the thread local variable if ( Connthreadlocal.get () = = null) {Connection conn = connectionmanager.getconnection (); Connthreadlocal.set (conn); return Conn;} else {//③ directly returns the thread-local variable return connthreadlocal.get ();}} public void Addtopic () {//④ Gets the statement stat = getconnection () corresponding to the thread from Threadlocal. createstatement ();}} </connection></connection>
When using Topicdao, different threads first determine if Connthreadlocal.get () is null, or NULL, indicating that the current thread does not have a corresponding connection object. At this point, a connection object is created and added to the local thread variable, and if it is not NULL, the current thread already has the connection object, which can be used directly. This ensures that different threads use thread-related connection and do not use the connection of other threads. Therefore, this topicdao can be done singleton share.
Of course, this example itself is very rough, put connection threadlocal directly in DAO can only do this DAO's multiple methods sharing connection without thread safety problem, but cannot share the same connection with other DAO, To do the same transaction multiple DAO share the same connection, you must use Threadlocal to save the connection in a common external class. But this example basically illustrates spring's approach to stateful thread security.
Java Learning Note--threadlocal