The correct posture for thread safety with the Threadlocal class

Source: Internet
Author: User

As you often know, the Threadlocal class can help us implement thread security, which associates a value in a thread with the object that holds the value. Threadlocal provides access interfaces or methods such as get and set, which have a separate copy of each thread that uses the variable, so get always returns the most recent value set by the current execution thread when it calls set. Conceptually, we understand threadlocal<t> as an object that contains map<thread,t>, where map's key is used to identify different threads, and map's value holds a certain value for that thread. But the implementation of threadlocal is not so, and we use threadlocal in such a way that it is not really thread-safe to do so.

Let's take an example to illustrate that number is a class that has a member variable of type int:

 Public classNumber {Private intnum;  Public intGetnum () {returnnum; }     Public voidSetnum (intnum) {         This. num =num; } @Override PublicString toString () {return"Number [num=" + num + "]"; }    }

Notsafethread is a class that implements the Runable interface, where we create a threadlocal<number>-type variable value that holds the NUM values for different threads, and then we start with a thread pool of 5 threads, We want to use the Threadlocal class to hold a copy of the number type for 5 different threads, eradicate the sharing of the variable, and return the number object associated with the thread when calling the Get () method of the Threadlocal class. And these number objects we want them to be able to track their own count values:

 Public classNotsafethreadImplementsRunnable { Public StaticNumber number =NewNumber ();  Public Static inti = 0;  Public voidrun () {//each thread counts plus oneNumber.setnum (i++); //store it in ThreadlocalValue.set (number); //Output num ValueSystem.out.println (Value.get (). Getnum ()); }     Public StaticThreadlocal<number> value =NewThreadlocal<number>() {    };  Public Static voidMain (string[] args) {Executorservice Newcachedthreadpool=Executors.newcachedthreadpool ();  for(inti = 0; I < 5; i++) {Newcachedthreadpool.execute (NewNotsafethread ()); }    }}

Startup program: Output results

01234

It looks like everything is fine, each thread seems to have its own storage space for number, but we simply add a delay before the output:

 Public classNotsafethreadImplementsRunnable { Public StaticNumber number =NewNumber ();  Public Static inti = 0;  Public voidrun () {//each thread counts plus oneNumber.setnum (i++); //store it in ThreadlocalValue.set (number); //2 seconds Delay        Try{TimeUnit.SECONDS.sleep (2); } Catch(interruptedexception e) {//TODO auto-generated Catch block        }        //Output num ValueSystem.out.println (Value.get (). Getnum ()); }     Public StaticThreadlocal<number> value =NewThreadlocal<number>() {    };  Public Static voidMain (string[] args) {Executorservice Newcachedthreadpool=Executors.newcachedthreadpool ();  for(inti = 0; I < 5; i++) {Newcachedthreadpool.execute (NewNotsafethread ()); }    }}

Run the program, output:

44444

Why does each thread output 4? Did they not save their own copy of the number alone? Why can other threads still be able to modify this value? Let's take a look at the source code of Threadlocal:

     Public void set (Object obj)    {        = thread.currentthread ();//gets current        thread = getmap (thread)        ; if NULL )            Threadlocalmap.set (this, obj);         Else             createmap (thread, obj);    }

One of the Getmap methods:

    threadlocal.threadlocalmap getmap (thread thread)    {        return  thread.inheritablethreadlocals;//returns the member variable of thread    }

As you can see, these thread-specific values are saved in the current thread object and are not saved in the Threadlocal object. And we find that the thread object holds a reference to the object, so that when other threads make changes to the object that the reference points to, the values that are saved in the thread object of the current threads change. This is why the above program will output the same result: 5 threads hold a reference to the same number object, while the thread sleeps 2s, other threads modify the NUM variable so that they end up with the same result.

So, the threadlocal "has a separate copy for each thread that uses the variable, so get always returns the most recent value set by the current execution thread when it calls set." The "independent copy" in this sentence, which we understand as "thread-local storage" can only be an object unique to each thread and not shared with other threads, presumably:

     Public Static New Threadlocal<number>() {        public number InitialValue () {// Initialize the values saved for each thread             returnnew number ();        }    };

Or

     Public void run () {        value.set (new number ());    }

All right... At this point you will say: What is the use of this threadlocal, each thread of its own new object to use, only its own use of this object without sharing, then the program is certainly thread-safe. So it looks like I'm not using threadlocal, and when I need to use an object, it's OK to just use the new one for this thread.

It is true that threadlocal is not used to allow multiple threads to work together on an object, but I have a thread A, where I need to use an object o, the object o is called in a number of places within this thread A, and I do not want to pass this object o as a parameter between multiple methods, so I put this object o into theadlocal so that anywhere within this thread A, as long as the method in thread A does not modify the object o, I can fetch the same variable O.

To give an example in practice, for example, we have a bank of the Bankdao class and a personal account of the Peopledao class, now requires individuals to transfer to the bank, there is an account reduction method in the Peopledao class, Bankdao class has an account increase method, Then these two methods must use the same connection database connection object at the time of invocation, if they use two connection objects, two transactions will be turned on, and there may be a decrease in personal account and no increase in bank account. With the same connection object, the application may be set as a global database connection object, thus avoiding passing a connection object when each method is called. The problem is that when we set the connection object to a global variable, you can't guarantee that another thread will shut down the connection object, and then there will be a thread-safety problem. The solution is to use threadlocal to get the connection object in the transfer operation, so that the same connection object can be fetched from the threadlocal in the thread that calls the personal account reduction and the increase in the bank account. And this connection object is unique to the transfer operation and is not affected by other threads, ensuring thread safety.

The code is as follows:

 Public classConnectionholder { Public StaticThreadlocal<connection> Connectionholder =NewThreadlocal<connection>() {    };  Public StaticConnection getconnection () {Connection Connection=Connectionholder.get (); if(NULL==connection) {Connection=drivermanager.getconnection (Db_url);        Connectionholder.set (connection); }        returnconnection; }}

In the framework, we need to associate a transactional context (Transaction context) with a thread in execution. By saving the transaction context in a static Threalocal object, which is certainly not shared with other threads, it is easy to implement this function: When the framework code needs to determine which transaction is currently running, it simply reads the transaction context from the Threadlocal object. This mechanism is convenient because it avoids the need to pass execution context information when each method is called, but it also uses the mechanism's code to be coupled with the framework.

  

The correct posture for thread safety with the Threadlocal class

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.