[Java] ThreadLocal

Source: Internet
Author: User

[Java] ThreadLocal
We know that Spring makes it easier for developers to use various data persistence technologies through various template classes. These template classes are thread-safe, that is, multiple DAO can reuse the same template instance without conflict. We use the template class to access the underlying data. Based on the persistence technology, the template class needs to bind resources for data connections or sessions. However, these resources are non-thread-safe, that is, they cannot be shared by multiple threads at the same time. Although the template class acquires data connections or sessions through the resource pool, the resource pool solves the cache issue of data connections or sessions, not the thread security issue of data connections or sessions.

According to traditional experience, if an object is non-thread-safe, in a multi-threaded environment, the access to the object must use synchronized for thread synchronization. However, the template class does not adopt the thread synchronization mechanism because thread synchronization reduces concurrency and affects system performance. In addition, it is very challenging to solve thread security through code synchronization, which may increase the implementation difficulty several times. What kind of magic does the template rely on to solve the thread security problem without thread synchronization? The answer is ThreadLocal!

ThreadLocal plays an important role in Spring. It has appeared in Bean, transaction management, task scheduling, AOP and other modules that manage request scopes, and plays an important role. To understand the underlying technology of Spring transaction management, ThreadLocal is a mountain fortress that must be overcome.

What is ThreadLocal?

As early as JDK 1.2, java. lang. ThreadLocal is provided. ThreadLocal provides a new way of thinking to solve the concurrent problem of multi-threaded programs. Using this tool class, you can easily compile beautiful multi-threaded programs.
ThreadLocal, as its name implies, is not a thread, but a localized object of the thread. When ThreadLocal is used to maintain a variable for a multi-threaded object, ThreadLocal allocates an independent copy of the variable for each thread that uses the variable. Therefore, each thread can change its own copy independently without affecting the copies corresponding to other threads. From the thread perspective, this variable is like a Local variable of the thread, which is also the meaning of "Local" in the class name.

Thread Local variables are not new to Java. Many languages (such as ibm xl and FORTRAN) provide thread local variables at the syntax level. Java does not provide language-level support, but uses a flexible method to provide support through the ThreadLocal class. Therefore, the code for writing thread local variables in Java is relatively clumsy, Which is why thread local variables are not widely used by Java developers.


ThreadLocal Interface Method

ThreadLocal class interface is very simple. There are only four methods. Let's take a look at it first.

  • Void set (Object value) sets the value of the local variable of the current thread;
  • Public Object get () This method returns the local variable of the thread corresponding to the current thread;
  • Public void remove () deletes the local variable value of the current thread to reduce memory usage. This method is newly added to JDK 5.0. It should be noted that when the thread ends, the local variables of the thread will be automatically reclaimed, so explicitly calling this method to clear the local variables of the thread is not a required operation, but it can speed up memory recovery;
  • Protected Object initialValue () returns the initial value of the local variable of the thread. This method is a protected method, apparently designed to overwrite the subclass. This method is a delayed call method. It is executed only once when the thread calls get () or set (Object) for 1st times. The default implementation in ThreadLocal directly returns a null value.


    It is worth mentioning that in JDK5.0, ThreadLocal already supports generics, and the class name of this class has changed to ThreadLocal. . The API methods are also adjusted accordingly. The new API methods are void set (T value), T get (), and T initialValue ().

    How does ThreadLocal maintain copies 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 variable 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. We can provide a simple implementation version:

    Code List 9-3 SimpleThreadLocal
    Java code
    1. Public class SimpleThreadLocal {
    2. Private Map valueMap = Collections. synchronizedMap (new HashMap ());
    3. Public void set (Object newValue ){
    4. // ① The key is the thread object and the value is a copy of the variable of the thread
    5. ValueMap. put (Thread. currentThread (), newValue );
    6. }
    7. Public Object get (){
    8. Thread currentThread = Thread. currentThread ();
    9.  
    10. // ② Return the variable corresponding to this thread
    11. Object o = valueMap. get (currentThread );
    12.  
    13. // ③ If it does not exist in Map, store it in Map.
    14. If (o = null &&! ValueMap. containsKey (currentThread )){
    15. O = initialValue ();
    16. ValueMap. put (currentThread, o );
    17. }
    18. Return o;
    19. }
    20. Public void remove (){
    21. ValueMap. remove (Thread. currentThread ());
    22. }
    23. Public Object initialValue (){
    24. Return null;
    25. }
    26. }

      Although the ThreadLocal implementation version in code listing 9 3 seems naive, it is very similar to the ThreadLocal class provided by JDK in terms of implementation ideas.

      A TheadLocal instance

      Next, let's take a look at the specific usage of ThreadLocal through a specific instance.

      Code List 9-4 SequenceNumber
      Java code
      1. Package com. baobaotao. basic;
      2.  
      3. Public class SequenceNumber {
      4.  
      5. // ① Overwrite the initialValue () method of ThreadLocal through an anonymous internal class and specify the Initial Value
      6. Private static ThreadLocal SeqNum = new ThreadLocal (){
      7. Public Integer initialValue (){
      8. Return 0;
      9. }
      10. };
      11.  
      12. // ② Obtain the next Sequence Value
      13. Public int getNextNum (){
      14. SeqNum. set (seqNum. get () + 1 );
      15. Return seqNum. get ();
      16. }
      17.  
      18. Public static void main (String [] args)
      19. {
      20. SequenceNumber sn = new SequenceNumber ();
      21.  
      22. // ③ Three threads share the sn, each generating a serial number
      23. TestClient t1 = new TestClient (sn );
      24. TestClient t2 = new TestClient (sn );
      25. TestClient t3 = new TestClient (sn );
      26. T1.start ();
      27. T2.start ();
      28. T3.start ();
      29. }
      30. Private static class TestClient extends Thread
      31. {
      32. Private SequenceNumber sn;
      33. Public TestClient (SequenceNumber sn ){
      34. This. sn = sn;
      35. }
      36. Public void run ()
      37. {
      38. // ④ Each thread generates three sequence values
      39. For (int I = 0; I <3; I ++ ){
      40. System. out. println (thread [+ Thread. currentThread (). getName () +
      41. ] Sn [+ sn. getNextNum () +]);
      42. }
      43. }
      44. }
      45. }

        Generally, we define a subclass of ThreadLocal by using an anonymous internal class to provide the initial variable value, as shown in Area ①. The TestClient thread generates a set of serial numbers. At ③, we generate three testclients that share the same SequenceNumber instance. Run the above Code and output the following results on the console:

        Reference 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]

        Test the output result information. We find that the serial numbers generated by each thread share the same Sequence Number instance, but they do not interfere with each other, but they each generate independent serial numbers, this is because we provide separate copies for each thread through ThreadLocal.

        Comparison with Thread synchronization mechanism

        What are the advantages of ThreadLocal over thread synchronization? ThreadLocal and thread synchronization mechanisms are designed to solve the access conflict between the same variables in multiple threads.

        In the synchronization mechanism, the object lock mechanism ensures that only one thread accesses the variable at a time. At this time, the variable is shared by multiple threads. The synchronization mechanism requires the program to carefully analyze when to read and write the variable, and when to lock an object, when to release the object lock and other complicated issues, it is relatively difficult to design and write the program.

        ThreadLocal solves multi-thread concurrent access from another perspective. ThreadLocal provides an independent copy of variables for each thread, thus isolating multiple threads from Data Access conflicts. Because every thread has its own copy of the variable, there is no need to synchronize the variable. ThreadLocal provides thread-safe object encapsulation. When writing multi-threaded code, you can encapsulate insecure variables into ThreadLocal.

        Because ThreadLocal can hold any type of objects, get () provided by JDK of lower versions returns Object objects and requires forced type conversion. However, JDK 5.0 solves this problem through generics and simplifies the use of ThreadLocal to a certain extent. The new ThreadLocal of JDK 5.0 is used in Code List 9-2. Version.

        To sum up, for the problem of multi-thread resource sharing, the synchronization mechanism adopts the "time-for-space" approach: Access serialization and object sharing. ThreadLocal adopts the "space-for-time" method: parallel access and exclusive object. The former provides only one copy of the variable, allowing different threads to queue for access, while the latter provides a copy of the variable for each thread. Therefore, the former can be accessed simultaneously without affecting each other.

        Spring uses ThreadLocal to solve thread security problems

        We know that in general, only stateless beans can be shared in multi-threaded environments. In Spring, most beans can be declared as singleton scopes. It is because Spring uses ThreadLocal to encapsulate non-thread-safe "State objects" of some beans (such as RequestContextHolder, TransactionSynchronizationManager, and LocaleContextHolder, it also makes them "State objects" of thread security, so stateful beans can work normally in multiple threads in singleton mode.

        Generally, Web applications are divided into three layers: presentation layer, service layer, and persistence layer. The corresponding logic is written in different layers. The lower layer opens function calls through interfaces to the upper layer. In general, all program calls from receiving requests to returning responses belong to the same thread, as shown in Figure 9-2.



        In this way, you can store some non-thread-safe variables as ThreadLocal as needed. In the same request response call thread, the same ThreadLocal variable accessed by all objects is bound to the current thread.
        The following example shows how Spring modifies stateful beans:

        Code List 9-5 TopicDao: Non-thread security
        Java code
        1. Public class TopicDao {
        2. // ① A non-thread-safe variable
        3. Private Connection conn;
        4. Public void addTopic (){
        5. // ② Reference a non-thread security variable
        6. Statement stat = conn. createStatement ();
        7. ...
        8. }
        9. }

          Because the conn at ① Is a member variable, because the addTopic () method is non-thread-safe, you must create a new TopicDao instance (not singleton) when using it ). The following uses ThreadLocal to transform the non-thread-safe state of conn:

          Code List 9-6 TopicDao: thread security
          Java code
          1. Import java. SQL. Connection;
          2. Import java. SQL. Statement;
          3. Public class TopicDao {
          4.  
          5. // ① Use ThreadLocal to save the Connection variable
          6. Private static ThreadLocal ConnThreadLocal = new ThreadLocal ();
          7. Public static Connection getConnection (){
          8.  
          9. // ② If connThreadLocal does not have the Connection corresponding to this thread to create a new Connection,
          10. // And save it to the local variable of the thread.
          11. If (connThreadLocal. get () = null ){
          12. Connection conn = ConnectionManager. getConnection ();
          13. ConnThreadLocal. set (conn );
          14. Return conn;
          15. } Else {
          16. // ③ Directly return the local variable of the thread
          17. Return connThreadLocal. get ();
          18. }
          19. }
          20. Public void addTopic (){
          21.  
          22. // ④ Obtain the corresponding thread from ThreadLocal
          23. Statement stat = getConnection (). createStatement ();
          24. }
          25. }

            When different threads use TopicDao, determine connThreadLocal first. whether get () is null. If it is null, it indicates that the current thread has no corresponding Connection object. In this case, create a Connection object and add it to the local thread variable. If it is not null, it indicates that the current thread already has a Connection object and can be used directly. This ensures that different threads Use thread-related connections instead of other threads. Therefore, this TopicDao can be shared by singleton.

            Of course, this example is rough. Placing the ThreadLocal of Connection directly on Dao can only achieve that thread security issues do not occur when multiple methods of the Dao share the Connection, but it cannot share the same Connection with other Dao. To share the same Connection with multiple Dao in the same transaction, ThreadLocal must be used in a common external class to save the Connection. However, this example basically illustrates Spring's solution to stateful thread security. Later in this chapter, we will explain in detail how Spring solves the problem of transaction management through ThreadLocal.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.