Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

The principle and usage of ThreadLocal

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "the principle and usage of ThreadLocal". In the operation of actual cases, many people will encounter such a dilemma. Next, let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Introduction to ThreadLocal

In terms of name, ThreadLocal is the combination of thread and local, that is, a thread has a variable copy of local. ThreadLocal provides a local copy of the thread, which means that each thread will have its own independent copy of the variable.

The method is concise and capable, and the class information and method list are as follows:

Example

A ThreadLocal variable is defined in the test class, which is used to save String type data. Two threads are created, which set the value, read the value, remove it and read it again.

Package com.declan.threadlocal;/** * @ author Declan * @ date 14:36 on 2019-08-16 * / public class ThreadLocalDemo {public static ThreadLocal threadLocal = new ThreadLocal (); public static void main (String [] args) {Thread thread1 = new Thread (()-> {/ / thread1 set the value threadLocal.set ("this is thread1's local") / / get the value System.out.println (Thread.currentThread (). GetName () + ": threadLocal value:" + threadLocal.get ()); / / remove the value threadLocal.remove (); / / get System.out.println again (Thread.currentThread (). GetName () + ": after remove threadLocal value:" + threadLocal.get ());}, "thread1") Thread thread2 = new Thread (()-> {/ / thread1 sets the value threadLocal.set ("this is thread2's local"); / / gets the value System.out.println (Thread.currentThread () .getName () + ": threadLocal value:" + threadLocal.get ()); / / removes the value threadLocal.remove () / / get System.out.println again (Thread.currentThread (). GetName () + ": after remove threadLocal value:" + threadLocal.get ());}, "thread2"); / / start two threads thread1.start (); thread2.start () }} result thread2: threadLocal value:this is thread2's localthread2: after remove threadLocal value:nullthread1: threadLocal value:this is thread1's localthread1: after remove threadLocal value:null

As can be seen from the results, each thread can have its own unique piece of data. After the remove does not affect each other, the data is emptied.

You can also see a situation from the above example:

If two threads operate on a variable at the same time, there is no influence on each other. In other words, it is obviously not used to solve some concurrency problems of shared variables, such as multi-thread collaboration.

Because the design philosophy of ThreadLocal is to share and become private, and it is already private, so why talk about sharing? For example, in the previous message queue, in the producer-consumer example, final LinkedList messageQueue = new LinkedList (); if the LinkedList is ThreadLocal, the producer uses one and the consumer uses one, what else is there to collaborate with?

But sharing becomes private, like concurrent serial, it may be suitable to solve the thread safety problem in some scenarios, because it looks like there is no shared variable, and not sharing is safe, but it does not exist to solve the thread safety problem.

Case analysis

There is a threadLocals variable in Thread of type ThreadLocal.ThreadLocalMap

ThreadLocalMap is the static inner class of ThreadLocal, a custom hash map designed to hold thread local variables

In other words, there is a "hashMap" in Thread that can be used to hold key-value pairs.

Set method

In this method, you accept the parameter, value of type T

First get the current thread, then call getMap (t)

This method is very simple, just return the "hashMap" inside the Thread directly (threadLocals is the default access right)

Go back to the set method, if the map is not empty, then take this as the value of key,value, that is, the ThreadLocal variable as the key

If map is empty, create a map for the thread and set the first set of values. Key is still the ThreadLocal variable.

In short:

Calling a set method of ThreadLocal will save the key-value pair with the variable of type ThreadLocal as key and the parameter as value in a "hashMap" inside the Thread.

Get method

Inside the get method, you still get the "hashMap" inside the current thread, and then use the current object this (ThreadLocal) as the key to get the value:

We have a different understanding of these two methods:

Each thread may manipulate a lot of ThreadLocal variables while it is running, so how do you tell them apart?

The intuitive understanding is that we want to get the value of a ThreadLocal variable for a thread

A good solution is to save it with the help of Map, with ThreadLocal variable as key and local value as value

Suppose the map is named: threadLocalsMap, and it can provide setter and getter methods to set and read. The inner part is:

ThreadLocalsMap.set (ThreadLocal key,T value)

ThreadLocalsMap.get (ThreadLocal key)

This can achieve the effect of thread-local, but is there any inconvenience? What we define internally is the ThreadLocal variable, but only used as a key? Is it more convenient to get values directly through ThreadLocal?

How can the inversion of data reading be achieved? Because the Bijing value is indeed stored in Thread.

In fact, it is also very simple, just need to convert internally, for the following two methods, we need ThreadLocal as key

ThreadLocalsMap.set (ThreadLocal key,T value)

ThreadLocalsMap.get (ThreadLocal key)

And this key is not this ThreadLocal, isn't it this?

So:

ThreadLocal.set (T value) calls threadLocalsMap.set (this,T value) internally.

ThreadLocal.get () calls threadLocalsMap.get (this) internally.

So the summary is as follows:

A "hashMap" is stored inside each Thread, and the key is ThreadLocal. There are as many key as the thread operates on as many ThreadLocal.

You want to get the value of a ThreadLocal variable, which is ThreadLocal.get (), and inside is hashMap.get (this).

You want to set the value of a ThreadLocal variable, which is ThreadLocal.set (T value), and inside is hashMap.set (this,value).

The key lies in the internal "hashMap". ThreadLocal is just a "shell" for reading and writing inversion. It can be more concise and easy to use to read and write variables through this shell. The link of "inversion" is the getMap (t) method.

Remove method

The remove method is very simple. The current thread gets the hashMap,remove of the current thread.

Initial value

Looking back at the get method again, what happens if the specified thread does not have threadLocals or does not have set at all when it is first called?

As shown in the following figure, the setInitialValue method is called:

In the setInitialValue method, the initialValue method is called to get the initial value. If the thread does not have a threadLocals, it will be created. If so, the key-value pair of the ThreadLocal will be constructed with this initial value. To put it simply, if there is no set (or the internal threadLocals is null at all), then the value she returns is the initial value.

The internal initialValue method returns null by default, so if a ThreadLocal does not perform a set operation, the initial value is null:

How to set the initial value?

You can see that this is a protected method, so wouldn't it be nice to return a subclass that overrides this method? Implement the setting of the initial value in the subclass.

Summary

The value can be set by set method.

The value can be read through the get method. If it is not set, null; will be returned. If the initial value is provided using the withInitial method, the initial value will be returned.

The writing to the value will be removed through the remove method, and the get method will be called again. If the initial value is provided by the withInitial method, the initial value will be returned, otherwise null will be returned.

For the get method, it is obvious that if no initial value is provided, the return value is null. When using it, you need to be careful not to cause a NPE exception.

ThreadLocal,thread local, one per thread, what exactly does it mean?

What he means is that for a ThreadLocal type variable, each thread has a corresponding value, the name of this value is the name of the ThreadLocal type variable, and the value is the variable we set into, but if set sets a shared variable, then ThreadLocal is essentially the same object, isn't it?

If in doubt, this sentence can be understood like this:

For the same ThreadLocal variable a, each thread has a map,map with a key-value pair, the key is a, and the value is the value you saved, but is this value, after all, new for each thread? Or do you use the same one? This is your own problem!

ThreadLocal can make it possible for each thread to have a separate value, but if you have to use shared variables to set them to one, ThreadLocal will not be guaranteed. This is like an object, there are many references to it, each thread has a separate reference, but there is only one object at all. So, from this point of view, it is easier to understand why ThreadLocal is not designed to solve thread safety problems, because he will not do anything to ensure thread safety, his ability is to hold multiple references, whether these multiple references can guarantee multiple different objects, you decide!

So what we said at the beginning, the argument that ThreadLocal will create a copy of variables for each thread is not rigorous, it is that he has the ability to do this, but what object it is, it depends on what you set. Set itself will not interfere with your value.

Application scenario

As mentioned earlier, ThreadLocal is not appropriate for the previous producer-consumer example, because the problem model is to collaborate between multiple threads, not to privatize shared variables for thread safety.

For example, for deposits and withdrawals in a bank account, if two account objects are created with the help of ThreadLocal, there will be a problem. The initial value is 500. obviously, another 1000 yuan is deposited, and the total disposable amount is still 500yuan.

What kind of scene does ThreadLocal suit? Since it is one per thread, it is naturally suitable for the kind of scenario where you want each thread to have one (like nonsense).

One in a thread, that is, thread isolation, since it is one thread, the methods called in the same thread are shared, so sometimes ThreadLocal is used as a tool for passing parameters.

Because it ensures that the value in the same thread is unique, it is shared in all methods, which is equivalent to a global variable for all methods!

So it can be used to pass global parameters in the same thread.

Example

For the JavaWeb project, we all know about Session.

Ps: without introducing session here, open the browser and enter the URL. This will create a session, close the browser, and session will become invalid.

During this period, in multiple requests of a user, sharing the same session,Session saves a lot of information, some need to obtain information through Session, and some need to modify the information of Session.

Each thread needs an independent session, and many places need to operate Session, so there is a need for multiple methods to share Session, so session objects need to be shared among multiple methods.

If you do not use ThreadLocal, you can create a Session object within each thread and pass it as a parameter in multiple methods

Obviously, if you pass parameters explicitly every time, it will be tedious and error-prone.

This kind of scenario is suitable for using ThreadLocal

The following example simulates an example of multiple methods sharing the same session, but session isolation between threads:

Package com.declan.threadlocal;/** * @ author Declan * @ date 16:07 on 2019-08-16 * / public class SessionDemo {/ * session variable definition * / static ThreadLocal sessionThreadLocal = new ThreadLocal (); / * get session * @ return * / public static Session getSession () {if (sessionThreadLocal.get () = = null) {sessionThreadLocal.set (new Session ()) } return sessionThreadLocal.get ();} / * * remove session * / public static void closeSession () {sessionThreadLocal.remove () } / * simulate a method to call session 1 * / public static void fun1 (Session session) {} / * simulate a method to call session 2 * / public static void fun2 (Session session) {} / * simulate session object * / static class Session {} public static void main (String [] Args) {Thread thread = new Thread (()-> {fun1 (sessionThreadLocal.get () Fun2 (sessionThreadLocal.get ()); closeSession ();}); thread.start ();}}

Therefore, the most basic usage scenario of ThreadLocal should be:

When each thread wants a unique variable (which is likely to be shared within the same thread), avoid the need for each thread to actively create the object (if it still needs to be shared, it also solves the problem of passing parameters back and forth), in other words, "how to elegantly solve the problem of isolation between threads and sharing within threads" Not to solve messy thread safety problems.

So if there are scenarios where you need thread isolation, it's not the same thing to think about ThreadLocal, not if you have some thread safety problem to solve, and then turn to ThreadLocal.

Note again:

ThreadLocal only has this ability, is that you can achieve a unique variable per thread, but if you set, it is not a new variable passed by new, that is, it is only understood as "a different reference for each thread", and the object is still that object (a bit like the value passed when the parameter is passed, the reference is passed to the object)

Summary

ThreadLocal can be used to elegantly solve the problem of isolated objects between threads, which must be created actively. With the help of ThreadLocal, there is no need to explicitly create objects in the thread, the solution is very elegant.

The set method in ThreadLocal does not guarantee that each thread will get a different object, so you need to do some processing on the logic (such as the getSession method in the above example, if the get of the ThreadLocal variable is null, then the new object) can really achieve thread isolation, depending on your own coding implementation, but if it is a shared variable, why do you put it in ThreadLocal?

So it is usually an object unique to the thread, created through new.

This is the end of the introduction to the principle and usage of ThreadLocal. Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report