A little bit of conquest ThreadLocal

What ThreadLocal
  as early as provided in java.lang.ThreadLocal version of JDK 1.2, ThreadLocal provides a new way to solve the problem of concurrent multi-threaded programs. Using this tool can be very simple class to write a beautiful multi-threaded programs.
  When using ThreadLocal variable maintenance, ThreadLocal provided for each thread using the variable independent variable copy, each thread can independently change their copy without affecting other threads corresponding copy.
  From the perspective of the thread of view, the target variable is like a thread local variable, which is meant to express the class name "Local".
  Therefore, the code to write thread-local variables in Java to be relatively few clumsy, thus causing thread-local variables are not well in the popularity of Java developers in.
ThreadLocal interface methods
ThreadLocal class interface is very simple, only four methods, let's take a look:
void the SET (Object value) Set the value of thread-local variables of the current thread.
public Object get () method returns the current thread corresponding to the thread-local variables.
public void remove () the value of the local variables of the current thread deleted, the purpose is to reduce memory usage, which is a new method for JDK 5.0. It should be noted that, when the end of the thread, the thread local variable should automatically be garbage, so explicitly call this method to clear the thread local variable is not required to operate, but it can speed up the recovery of memory speed.
protected Object initialValue () returns to the initial value of the thread local variables, which is a method of a protected, apparently to allow subclasses designed cover. This method is a method to delay calling, call get () or set (Object) when the execution thread the first time, and only performed once. The default ThreadLocal in direct returns a null.
  It is worth mentioning that in JDK5.0, ThreadLocal has support for generics, the class of the class name has become ThreadLocal. API methods been adjusted accordingly, the new version of the API methods are void set (T value), T get () and T initialValue ().
  How do ThreadLocal is to maintain a copy of each thread variables it? In fact, the idea is very simple realization: There is a Map in ThreadLocal class, a thread for each copy of the variable storage, key elements in the Map is thread object, and the value of the variable corresponding to a copy of the thread. We ourselves can provide a simple implementation version:

[java] view plain copy
package com.test;

TestNum class {public
// ThreadLocal covered by the initialValue ① anonymous inner classes () method, specifying the initial value
Private static ThreadLocal seqNum = new new ThreadLocal () {
public the initialValue Integer () {
return 0;
}
};

// ②获取下一个序列值  
public int getNextNum() {  
    seqNum.set(seqNum.get() + 1);  
    return seqNum.get();  
}  

public static void main(String[] args) {  
    TestNum sn = new TestNum();  
    // ③ 3个线程共享sn,各自产生序列号  
    TestClient t1 = new TestClient(sn);  
    TestClient t2 = new TestClient(sn);  
    TestClient t3 = new TestClient(sn);  
    t1.start();  
    t2.start();  
    t3.start();  
}  

private static class TestClient extends Thread {  
    private TestNum sn;  

    public TestClient(TestNum sn) {  
        this.sn = sn;  
    }  

    public void run() {  
        for (int i = 0; i < 3; i++) {  
            // ④每个线程打出3个序列值  
            System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn["  
                     + sn.getNextNum() + "]");  
        }  
    }  
}  

}

We define the subclass generally by way anonymous inner classes ThreadLocal provide an initial variable value, as in the example shown at ①. Generating a set of threads TestClient sequence number, the at ③, we generated three TestClient, they share the same TestNum instance. Running the above code, the following output results on the console:

thread[Thread-0] --> sn[1]
thread[Thread-1] --> sn[1]
thread[Thread-2] --> sn[1]
thread[Thread-1] --> sn[2]
thread[Thread-0] --> sn[2]
thread[Thread-1] --> sn[3]
thread[Thread-2] --> sn[2]
thread[Thread-0] --> sn[3]
thread[Thread-2] --> sn[3]

Inspection result information output, we found that although each thread ID generated share the same TestNum example, but they do not, interference may occur, but rather each independently generated sequence number, this is because we through each ThreadLocal a thread provides separate copies.

Compare Thread synchronization mechanism
  ThreadLocal thread synchronization mechanisms and what are the advantages compared to it? ThreadLocal and thread synchronization mechanisms are made to address multiple threads access the same variable conflict.
  In the synchronization mechanism by locking mechanism to ensure that the object of the same time only one thread access the variable. Then the variable is shared by multiple threads, using a synchronous mechanism requires careful analysis of program variables when read and write, when you need to lock an object, when to release the object lock complex issues, programming and writing the difficulty is relatively large.
  The ThreadLocal from another point of view to solve the multi-threaded concurrent access. ThreadLocal will provide a copy of the independent variables for each thread, thereby isolating the conflict on multiple threads access the data. Because each thread has its own copy of the variable, so there is no need for the variable sync. ThreadLocal provide a thread-safe shared objects, when writing multithreaded code can be encapsulated into the unsafe variables ThreadLocal.
  Since ThreadLocal can hold any type of object, the low version of JDK provided by get () returns an Object object, we need to cast. JDK 5.0 but a good solution to this problem by generics, to simplify the use of ThreadLocal to some extent, the code in Listing 92 on the use of new ThreadLocal JDK 5.0 version.
  To sum up, for multithreading issues of resource sharing, synchronization mechanisms adopted the way of "time for space", which uses a ThreadLocal way "trade space for time". The former provides only one variable, so that different threads access the queue, each thread while the latter offers a variable, it can be accessed simultaneously and independently of each other is.
  Spring uses ThreadLocal thread safety problem solving We know that in general, only stateless Bean can only be shared in a multithreaded environment, in Spring, the vast majority Bean can be declared as singleton scope. Bean is because some Spring Bean (such as RequestContextHolder, TransactionSynchronizationManager, LocaleContextHolder, etc.) using ThreadLocal Africa thread-safe state for processing, so that they become a thread-safe state, because there are state can be shared in multiple threads.
  Web applications generally divided into the presentation layer, service layer and persistence layer three levels, the preparation of the corresponding logic in different layers, the lower to the upper open through the interface call feature. In general, receiving a request to return a response procedure through which all calls belong to the same thread, shown in Figure 9-2:
all appreciated ThreadLocal let in
  the same thread through three so you may need to Some non-thread-safe variables ThreadLocal storage, the calling thread in response to the same request, all associated objects are referenced to the same variable.
  The following examples can reflect Spring stateful Bean transformation ideas:
the code in Listing 3 TestDao: non-thread-safe

[java] view plain copy
package com.test;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

the TestDAO class {public
Private Connection conn; // ① a non-thread-safe variable

public void addTopic() throws SQLException {  
    Statement stat = conn.createStatement();// ②引用非线程安全变量  
    // …  
}  

}

Since conn ① at the member variables, because addTopic () method is non-thread-safe, you must create a new instance of TopicDao (non-singleton) when in use. The following use of ThreadLocal conn this non-thread-safe "state" of the transformation:
Listing 4 TestDao: thread-safe

[java] view plain copy
package com.test;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class TestDaoNew {
// ①使用ThreadLocal保存Connection变量
private static ThreadLocal connThreadLocal = new ThreadLocal();

public static Connection getConnection() {  
    // ②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,  
    // 并将其保存到线程本地变量中。  
    if (connThreadLocal.get() == null) {  
        Connection conn = getConnection();  
        connThreadLocal.set(conn);  
        return conn;  
    } else {  
        return connThreadLocal.get();// ③直接返回线程本地变量  
    }  
}  

public void addTopic() throws SQLException {  
    // ④从ThreadLocal中获取线程对应的Connection  
    Statement stat = getConnection().createStatement();  
}  

}

When using different threads TopicDao, first determine connThreadLocal.get () whether it is null, if it is null, then the current thread has no corresponding Connection object, then creates a Connection object and thread to the local variables; if not is null, then the current thread already owns the Connection object to use it. Thus, to ensure that different threads use thread-related Connection, Connection without using other threads. Therefore, this can be done TopicDao singleton shared.
  Of course, this example itself is very rough, the DAO Connection of ThreadLocal can do directly on the thread safety problems do not occur when the Connection Sharing multiple methods of the DAO, but can not share the same with other DAO Connection, to do the same transaction multi-DAO share the same Connection, you must use the ThreadLocal Connection saved in a common external class.

ConnectionManager.java

[java] view plain copy
package com.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionManager {

private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {  
    @Override  
    protected Connection initialValue() {  
        Connection conn = null;  
        try {  
            conn = DriverManager.getConnection(  
                    "jdbc:mysql://localhost:3306/test", "username",  
                    "password");  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
        return conn;  
    }  
};  

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

public static void setConnection(Connection conn) {  
    connectionHolder.set(conn);  
}  

}

java.lang.ThreadLocal the realization
that in the end is how to achieve this ThreadLocal class "provide a different variable for each thread copy" of it? First look at the source code of ThreadLocal set () method is how to achieve:

[java] view plain copy
/**
* Sets the current thread’s copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread’s copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

In this way we see inside, first obtain a current thread and related ThreadLocalMap by getMap (Thread t) method, and then set the value of the variable to the ThreadLocalMap object, of course, if the acquired ThreadLocalMap object is empty, it is by createMap method creates.

Thread isolation of secrets, lies ThreadLocalMap this class. ThreadLocalMap ThreadLocal class is a static inner class that implements key-value pairs set and get (Map object comparison to understand), each thread has a separate ThreadLocalMap copy of it stored value, can only be current thread to read and modify. ThreadLocal copy of each class by operating ThreadLocalMap a specific thread, thereby achieving isolation variable access in different threads. Because each thread variables are unique to their own, they will not have concurrency error. Another point is that, ThreadLocalMap store key-value pairs in the key point is the object of this ThreadLocal objects, and value is the object of your set up.

In order to deepen understanding, we then look to achieve getMap and createMap methods that appear in the above code:

[java] view plain copy
/**

  • Get the map associated with a ThreadLocal. Overridden in
  • InheritableThreadLocal.
  • @param t the current thread
  • @return the map
    */
    ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
    }

/**

  • Create the map associated with a ThreadLocal. Overridden in
  • InheritableThreadLocal.
  • @param t the current thread
  • @param firstValue value for the initial entry of the map
  • @param map the map to store.
    */
    void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

Then look again get ThreadLocal class () method:

[java] view plain copy
/**

  • Returns the value in the current thread’s copy of this
  • thread-local variable. If the variable has no value for the
  • current thread, it is first initialized to the value returned
  • by an invocation of the {@link #initialValue} method.
  • @return the current thread’s value of this thread-local
    */
    public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null)
    return (T)e.value;
    }
    return setInitialValue();
    }

Look setInitialValue () Method:

[java] view plain copy
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}

When the value of the current acquisition and thread-bound, ThreadLocalMap ThreadLocal objects are objects of this point is to find the key, of course, the previous set () method code is echoes.

Further, we can create different ThreadLocal instance variables to achieve more isolated in access between different threads, why you can do? Because different ThreadLocal objects as different keys, of course, a different value may be set in the object ThreadLocalMap thread. By ThreadLocal objects, a distinction shared values ​​and multiple values ​​in multiple threads, just as you store a key-value pairs in a HashMap object and a plurality of key-value pairs, like, nothing more.

Summary
  ThreadLocal thread safety problem is the way to solve a very good, it solves the problem of variable concurrent access conflicts by providing a separate thread for each copy of the variable. In many cases, ThreadLocal than using synchronized thread synchronization mechanisms to address security issues simpler, more convenient, and the results of the program have higher concurrency.
ConnectionManager.java

[java] view plain copy
package com.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionManager {

private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {  
    @Override  
    protected Connection initialValue() {  
        Connection conn = null;  
        try {  
            conn = DriverManager.getConnection(  
                    "jdbc:mysql://localhost:3306/test", "username",  
                    "password");  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
        return conn;  
    }  
};  

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

public static void setConnection(Connection conn) {  
    connectionHolder.set(conn);  
}  

}

Postscript
  see friends comment is fierce, even on ThreadLocalMap not ThreadLocal inside, but inside this Thread comments have emerged, so with this postscript, paste the following first jdk source, the source of the most persuasive.

[java] view plain copy
/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
static class ThreadLocalMap {…}

Source code is more, which is a natural source in ThreadLocal inside, there are screenshots as evidence.

This article is himself in learning the ThreadLocal, on a whim, looked deep source of such thinking role, scope, and then think of the traditional synchronize shared variables thread-safety problems are compared and summarized Bowen, a summary then that is a lock mechanism is time for space, carried a copy storage space for time.

Published 33 original articles · won praise 0 · Views 853

Guess you like

Origin blog.csdn.net/ninth_spring/article/details/104417537