Threadlocal Implementation & usage-lockless thread Blocking

Source: Internet
Author: User

Although it can be said that many programmers will use threadlocal, I believe that most programmers do not know threadlocal, while most programmers who use threadlocal only know it, but do not know why. Therefore, programmers who use threadlocal are often imported into the trap. In fact, many of Java's advanced mechanism series are a double-edged sword, which has advantages and disadvantages, so our approach is to find the balance between advantages and disadvantages, and the best way to solve the problem.

 

This article first describes what threadlocal can do, then explains how to use it based on the reason for the function, and finally explains where the thread is located and how to avoid it.

 

Threadlocal definition and usage Overview (my understanding ):

It is a thread-level variable, absolutely safe in the concurrency mode, and a standard usage of thread closures (except for local variables), even if you define it as static, it is also thread-safe.

 

What can threadlocal do?

This sentence is hard to say. Let's take a look at some difficult solutions encountered in the actual project: When you enter some methods in the project based on some parameter calls, and then call the methods, and then call methods across objects. at many levels, these methods may use some similar parameters. For example, after parameters A, B, C, and a call B in, B needs parameters B and C, while B needs parameters A and B to call method C. At this time, B has to pass all the parameters to Method B, and so on. If there are many methods to call, at this time, the parameters will become more and more complex. In addition, when the program needs to add parameters, it needs to add parameters one by one for the relevant methods. Yes, it is very troublesome. I believe you have also encountered this problem, this is also a common processing method in the object-oriented language of C. However, our simple solution is to package it into an object and pass it in. This problem can be solved by adding the attribute of the object, however, objects are usually meaningful. In some cases, adding non-extended attributes to simple object packaging may make the definition of Class very strange, so in these cases, when we construct such complex programs, we use scope-like scopes. The name and usage of the class are more common. Similar to the scope with the context, session, request, and page levels in a web application, threadlocal can also solve such problems, however, it is not very suitable for solving such problems. In the early stage, it is not passed in the scope and object mode, and it is considered that the parameter will not be added. When a parameter is added, it is found that many places need to be changed. In order not to break the code structure, there may also be too many parameters, which has reduced the readability of the method code and added threadlocal for processing. For example, when one method calls another method, eight parameters are passed in. By calling the nth method layer by layer, one of the parameters is passed in. At this time, a parameter must be added to the last method, it is natural for the first method to become nine parameters, but at this time, related methods will be implicated, making the code bloated.

The above mentioned threadlocal is a powerful method, but it is not particularly recommended. It also has some similar methods for use, that is, there are many dynamic calls at the framework level, some protocols need to be met during the call process. Although the protocol will be used as common as possible, many extended parameters are not easy to consider completely when defining the protocol and the version is also upgraded at any time, however, the framework extension also needs to meet the versatility and downward compatibility of interfaces, while we need threadlocal for some extension content for convenient and simple support.

To put it simply, threadlocal converts some complex system extensions into simple definitions, making it easy to relate the components of relevant parameters. The following is an example:

In the spring Transaction Manager, the connection obtained from the data source is put into threadlocal. After the program is executed, it gets the connection from threadlocal and then performs commit and rollback. in use, ensure that the connection obtained by the program through datasource is obtained from spring. Why is this operation required? Because the Business Code is completely determined by the application, however, the framework cannot require business code writing. Otherwise, the framework will lose the benefits of preventing business code from managing connection. After the Business Code is cut in, spring does not pass in a connection to the Business Code area. It must be stored in one place. When the underlying layer obtains the connection of the same datasource through frameworks such as ibatis and spring JDBC, it will call to obtain according to the rules agreed by spring. Because the execution process is processed in the same thread, the same connection is obtained to ensure commit, Rol During lback and business operations, the same connection is used, because only the same conneciton can guarantee transactions, otherwise the database itself does not support transactions.

 

In fact, threadlocal plays an important role in many concurrent programming applications. It does not lock and easily closes the thread, it does not need to allocate new space every time like a local variable. Because many spaces are thread-safe, they can reuse the thread's private buffer.

 

How to Use threadlocal?

Define an appropriate location in the systemThreadlocalVariable, which can be definedPublic staticType (A threadlocal object is created directly). To add data to it, set (object) is used. To obtain data, get () is used. To delete elements, remove () is used (), other methods are notPublicIs not recommended.

The following is a simple example (code snippet 1 ):

Public class threadlocaltest2 {public final static threadlocal <string> test_thread_name_local = new threadlocal <string> (); Public final static threadlocal <string> test_thread_value_local = new threadlocal <string> (); public static void main (string [] ARGs) {for (INT I = 0; I <100; I ++) {final string name = "thread-[" + I + "]"; final string value = string. valueof (I); New thread () {public void run () {try {test_thread_name_local.set (name); test_thread_value_local.set (value); calla () ;}finally {test_thread_name_local.remove (); test_thread_value_local.remove ();}}}. start () ;}} public static void calla () {callb () ;}public static void callb () {New threadlocaltest2 (). callc ();} public void callc () {calld ();} public void calld () {system. out. println (test_thread_name_local.get () + "\ t = \ t" + test_thread_value_local.get ());}}

Here, we simulate the 100 threads for separate access settings.NameAndValue, IntentionallyNameAndValueThe value is set to the same, to see if there is a concurrency problem, the output can be seen that the thread output is not output in order, it indicates that it is executed in parallel, while the threadNameAndValueIt can correspond to each other. When multiple methods are called in the middle, the parameters in the actual call are not passed. How can we obtain the corresponding variables, however, in actual systems, cross-classes are often simulated only in one class. In fact, cross-classes are the same result. You can simulate them by yourself.

 

I believe that many programmersThreadlocalIt is amazing to see how it works without passing parameters and using it like a local variable, in fact, we can see that it is a setup method, and the name should be related to the thread, so let's talk about it. Let's take a look at its source code, since we use set, get, and remove most, we can start with set:

The Set (t obj) method is (code snippet 2 ):

public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }

First obtain the current thread, just like the guess, then there isGetmapMethod, passed in the current thread. First we can understand that this map is a map related to the thread. If it is not empty, we will perform the set operation, this is similar to the put Operation of hashmap, that is, writing a piece of data to the map. If it is null, call the createmap method (Code snippet 3):

void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }

A threadlocalmap is created and the passed parameters and the current threadlocal are written into the K-V structure (Code snippet 4):

       ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {            table = new Entry[INITIAL_CAPACITY];            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);            table[i] = new Entry(firstKey, firstValue);            size = 1;            setThreshold(INITIAL_CAPACITY);        }

The structure details of threadlocalmap are not described here. You only need to know that its implementation is similar to that of hashmap, but there are no methods or implements map, because it does not want you to obtain a map for further operations in some ways (such as reflection), it is a static internal class in threadlocal, the default type, only in Java. the classes below Lang can be referenced to it, so you can think that thread can be referenced to it.

 

Let's take a look at the getmap method, because I only know that the obtained map is thread-related, andCode snippet 3When there is a T. threadlocalmap = new threadlocalmap (this, firstvalue), I believe you should understand a bit that this variable should come from the thread. Let's go through the getmap method to see it:

ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }

Yes, it is from the thread, and this thread is exactly the current thread, so let's take a look at the definition:

ThreadLocal.ThreadLocalMap threadLocals = null;

This attribute is in the Thread class, that is, each thread has a threadlocalmap by default, which is used to store local variables at the Thread level. Generally, you cannot assign a value to it, this assignment is usually insecure.

 

It seems that it is a bit messy and don't worry. Let's look back and explore the following ideas:

1. A thread has a property similar to hashmap, but its name is threadlocalmap. This property is of the default type, therefore, all classes in the same package can be referenced. Because it is a local variable of the thread, each thread has its own independent map, which does not conflict with each other, therefore, no conflict exists between threadlocal and static threads.

2. threadlocal and thread are under the same package. You can reference this class and operate on it. In this case, threadlocal defines each one and uses this as the key, the value you pass in is the value, and this is the threadlocal defined by you. Therefore, different threadlocal variables use set, so data does not conflict with each other, because their keys are different, of course, after two set operations are performed on the same threadlocal, the last operation prevails.

3. In summary, threadlocal can be used like local variables in parallel between threads, and the thread is secure, and data between different threadlocal variables does not conflict with each other.

 

Let's continue to look at the get and remove methods, which is actually simple:

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();    }

Call the getmap method according to the current thread, that is, call T. threadlocalmap, and then look in the map, note that the map finds the entry, that is, the basic structure of the K-V, because you set to write only a value, so it will set an E. value to return the value you write, because the key is threadlocal itself. You can see that map. getentry is also obtained through this.

Similarly, the Remove Method is:

public void remove() {         ThreadLocalMap m = getMap(Thread.currentThread());         if (m != null)             m.remove(this);     }

Similarly, map is obtained based on the current thread. If it is not empty, remove. Use this to remove the map.

In addition (), what are the pitfalls of forgetting to write, and what are the pitfalls of threadlocal? We should be able to see from the above, this threadlocal-related object is bound to a map, and this map is an attribute of the thread, so there is a problem, if you do not remove it yourself, or if you do not know when to remove it in your program, the thread will not log out and the data that is set will not be logged out.

On the other hand, unless you clearly know where the object should be set and where to remove it in the Code, if it is fuzzy, it is likely that your code will not go to the remove position, it may cause some logic problems. In addition, if you do not remove it, you have to wait for the thread to log out. In many application servers, threads are reused, because there is still overhead in the kernel allocation thread, it is difficult for threads in these applications to be deregistered. Therefore, the data written to threadlocal is naturally not easily deregistered, these may be accidentally hidden and used when we use some open-source frameworks, which may lead to problems. Finally, we found that the data in OOM came from threadlocalmap, I still don't know where the data is set, so you should pay attention to this pitfall. More than one person may have been in this pitfall.

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.