brief introduction

Look from the name ,ThreadLocal That is to say thread and local The combination of , That's one thread There is one local Variable copy of
ThreadLocal A local copy of the thread is provided , That is, each thread will have its own independent copy of the variable
The method is simple and concise , The class information and methods are listed below

Example

One is defined in the test class ThreadLocal Variable , Used to hold String Type data
Two threads were created , Set values separately , Read the values , Remove and read again
package test2;
/**
* Created by noteless on 2019/1/30. Description:
*/
public class T21 {
// Definition ThreadLocal Variable
static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
//thread1 Set the value of
threadLocal.set("this is thread1's local");
// Get value
System.out.println(Thread.currentThread().getName()+": threadLocal value:" + threadLocal.get());
// Remove the value
threadLocal.remove();
// Once again
System.out.println(Thread.currentThread().getName()+": after remove threadLocal value:" + threadLocal.get());
}, "thread1");
Thread thread2 = new Thread(() -> {
//thread2 Set the value of
threadLocal.set("this is thread2's local");
// Get value
System.out.println(Thread.currentThread().getName()+": threadLocal value:" + threadLocal.get());
// Remove the value
threadLocal.remove();
// Once again
System.out.println(Thread.currentThread().getName()+": after remove threadLocal value:" + threadLocal.get());
}, "thread2");
thread1.start();
thread2.start();
}
}
Execution results
You can see that from the results , Each thread can have its own unique piece of data , They don't affect each other
remove after , Data is cleared
 
A case can also be seen from the above example :
If two threads operate on a variable at the same time , There is no effect on each other , let me put it another way , This is clearly not intended to solve some concurrency problems with Shared variables , Like multithreaded collaboration
because ThreadLocal The design concept of Shared to private , It's already private , Talk about sharing ?
Like the previous message queue , In the producer-consumer example
  final LinkedList<Message> messageQueue = new LinkedList<>();
If this LinkedList yes ThreadLocal Of , The producer USES a , Consumers use a , What else ?
But sharing becomes private , Like concurrent to serial , Thread safety issues may be appropriate for some scenarios , Because it looks like there are no Shared variables , Do not share is safe , But it doesn't exist to solve thread-safety problems

Implementation analysis

stay Thread There is one of them. threadLocals Variable , The type is ThreadLocal.ThreadLocalMap
and ThreadLocalMap It is ThreadLocal The static inner class of , It is a design for preservation thread local Custom of a variable hash map
All operations are private , That is, no method of operation is exposed , So it can only be in ThreadLocal Used in
We're not going to go into that , It's simply a hash map, Used to save key-value pairs
in other words Thread There is one of them. “hashMap” Can be used to save key-value pairs

set Method

to glance at ThreadLocal Of set Method
In this method , Accept parameters , The type is T Of value
First, get the current thread , And then call getMap(t)
This method is also very simple , Just go back Thread The inside one “hashMap”(threadLocals Is the default access )
Continue to back set Method , If this map Not empty , So in order to this by key,value Value , That is to say ThreadLocal Variable as key
If map It's empty , So go ahead and create one for this thread map , And set the first set of values ,key It's still this ThreadLocal Variable
in short :
A call to a ThreadLocal Of set Method , Will : With this ThreadLocal The variable of type is key, Parameter is value This key value pair , Save in Thread One inside “hashMap” in

get Method

stay get The inside of the method is still the inside of the current thread “hashMap”, Then take the current object this(ThreadLocal) As key, Fetch the value
Let's think about these two methods in a different way :
Each thread may run during the process , It could be a lot of work ThreadLocal Variable , How to distinguish one from the other ?
The intuition is that , We want to get one of these threads ThreadLocal The value of the variable
A good solution is the help Map Preservation ,ThreadLocal Variable as key,local Value as value
Suppose this map be known as :threadLocalsMap, Can provide setter and getter Method to set and read , For internal
  • threadLocalsMap.set(ThreadLocal key,T value)
  • threadLocalsMap.get(ThreadLocal key)
So that's what we can do thread --- local The effect of , But whether there is some inconvenience ? What we define internally is ThreadLocal Variable , But just to do key Of ? Whether to go through directly or not ThreadLocal It's easier to get the values ?
How to do the inversion of data reading ? Because after all the values are really stored in Thread Medium
It's also very simple , Just do the conversion internally , For the following two methods , We all need ThreadLocal key
threadLocalsMap.set(ThreadLocal key,T value)
threadLocalsMap.get(ThreadLocal key) 
And this key No, that's it. ThreadLocal, No, it is. this Well
therefore :
  • ThreadLocal.set(T value) On internal calls threadLocalsMap.set(this,T value)
  • ThreadLocal.get() On internal calls threadLocalsMap.get(this)
So to sum up :
  • Every Thread There's one inside "hashMap",key by ThreadLocal, How many does this thread operate on ThreadLocal, Just how many key
  • You want to get one ThreadLocal The value of the variable , Namely ThreadLocal.get(), The internal is hashMap.get(this);
  • You want to set one ThreadLocal The value of the variable , Namely ThreadLocal.set(T value), The internal is hashMap.set(this,value);
The key is just the internal one “hashMap”,ThreadLocal Just read and write upside down “ shell ”, The shell can be more concise and easy to use for reading and writing variables
“ The horse ” The link between , Namely getMap(t) Method

remove Method

remove The method is also simple , Current thread , Gets the current thread's hashMap,remove

Initial value

Let's go back again get Method , If I call it the first time , The specified thread does not threadLocals, Or not at all set
What's going to happen ?
As shown in the figure below , Would call setInitialValue Method
stay setInitialValue In the method , Would call initialValue Method to get the initial value , If the thread does not threadLocals So it will create , If there is , I'm going to use this initial value to construct this ThreadLocal The key/value pair
In short , without set too ( Or the one inside of the root threadLocals Namely null Of ), So the value that she returns is the initial value
This internal initialValue Method returns by default null, So a ThreadLocal If it doesn't work set operation , So the initial value is zero null
How to set the initial value ?
You can see that , This is a protected Method , therefore Returns a subclass that overrides the method No. It'll be ok ? Implement the setting of the initial value in the subclass
stay ThreadLocal An inner class is provided in SuppliedThreadLocal, This inner class accepts a functional interface Supplier As a parameter , adopt Supplier Of get Method to get the initial value
Supplier Is a typical built-in functional interface , Without the participation , Return type T, Since it is a functional interface, it can be used directly Lambda The expression constructs the initial value !!!
How do I construct this inner class , And then we set the initialization parameters ?
Provides withInitial Method , The argument to this method is Supplier type , You can see , This method will take arguments , Through to the SuppliedThreadLocal Construction method of , Just return one SuppliedThreadLocal
let me put it another way , We do not hope to be able to ThreadLocal Subclasses of , Cover initialValue() Method , Are initial values provided ?
This withInitial It's a way to get there !
Use withInitial Method , Create one with an initial value ThreadLocal Variable of type , It can be seen from the results , We don't have any Settings , You can get the value
Make a little change , Add one more time set and remove, You can tell by the printout ,set after , The values used are the ones we just set
And once remove after , So we're still going to use the initial value
Be careful :
about initialValue Method coverage , Even if you don't provide this subclass and this method, that's fine , Because essentially you're going to return a subclass , And overrides this method
We can do it ourselves , You can also directly anonymous classes , As shown below : Created a ThreadLocal Subclasses of , covers initialValue Method

ThreadLocal < type > threadLocalHolder =new ThreadLocal < type > () {

public type initialValue() {

return XXX;

}

};

But obviously , After subclasses and methods are provided , We can use it Lambda Expression to operate on , More abstract

summary :

adopt set Method to set the value
adopt get Method can read a value , If you haven't set it , So it's going to return null; If used withInitial Method provides the initial value , Will return the initial value
adopt remove Method will remove the write to the value , Call again get Method , If used withInitial Method provides the initial value , Will return the initial value , Otherwise return to null
about get Method , Obviously if the initial value is not provided , The return value is null, In use is to be careful not to cause NPE abnormal
 
ThreadLocal,thread  local, One copy per thread , What does it mean ?
He means for one ThreadLocal Type variable , Each thread has a corresponding value , The name of the value is ThreadLocal The name of the type variable , Value is our set Variables that go in
But if set Shared variables are set , that ThreadLocal It's essentially the same object ?
"If in doubt , It's understandable
For the same ThreadLocal Variable a, One per thread map,map Each of them has a key-value pair ,key by a, The value is the value you saved
But this value , After all, each thread is brand new ? It's the same thing ? It's your problem !!!
ThreadLocal It is possible to have a separate value for each thread , But you have to use Shared variables to set them to one , that ThreadLocal There is no guarantee
It's like an object , There are many references to him , Each thread has a separate reference , But there is only one object
therefore , It's easier to understand from this perspective , Why do you say ThreadLocal It's not designed to solve thread safety problems , Because he doesn't do anything for thread safety, right , His ability is to hold multiple references , Are these multiple references guaranteed to be multiple different objects , You come to the decision
So that's what we started with ,ThreadLocal The idea that a copy of a variable will be created for each thread is not rigorous
He has the ability to do it , But what is it , It's still up to you set What is the ,set Itself does not interfere with your values
But we usually do it under the right circumstances new objects creating , This object is used inside the thread , It does not need to be accessed by another thread
As shown in the figure below , What you put in is a Shared variable , They are the same object

Application scenarios

As I said before , In the previous producer-consumer example , It is not suitable for use ThreadLocal, Because the problem model is all about collaboration between multiple threads , Rather than privatizing Shared variables for thread-safety reasons
such as , Deposits and withdrawals from bank accounts , With the aid of ThreadLocal Two account objects were created , There will be problems , Initial value 500, Ming Ming saved it again 1000 block , The total amount of disposable income is still 500
that ThreadLocal What kind of scene ?
Since it's one per thread , Nature is suitable for situations where you want one per thread ( Seems like crap )
One in a thread , That is, thread isolation , Since it's a thread, it's a thread , Then methods called in the same thread are Shared , So , Sometimes ,ThreadLocal Will be used as a parameter to pass the tool
Because it guarantees that the value in the same thread is unique , Then he shares in all the methods , For all methods , It's a global variable !
So it can be used to pass global parameters within the same thread
But be careful , because “ Global variables ” Is used for maintainability 、 Legibility is a challenge , In especial ThreadLocal This thread isolation , But methods are Shared “ Global variables ”
How do you guarantee that it must be a private variable that is independent ?
about ThreadLocal No variables are initialized , The return value is null
So you can judge , If the return value is null, Objects can be created , This ensures that each thread has a separate one , Unique , Unique variable

Example

about JavaWeb project , You know that Session
ps: Here is wrong session An introduction , Open the browser and enter the URL , So this is going to create one session, Close the browser ,session Is failure
In this period of time , Multiple requests from one user , Share the same session
Session It holds a lot of information , Some need to go through Session pick up information , Some need to be revised Session Information about
Each thread needs to be independent session, And there are a lot of things that need to be done Session, There is multi-method sharing Session The needs of , therefore session Objects need to be Shared among multiple methods
If not used ThreadLocal, You can create one in each thread Session object , Then pass it as an argument in multiple methods
Obviously , If you explicitly pass arguments every time , Cumbersome error-prone
This scenario is suitable for use ThreadLocal
 
The following example simulates multiple methods sharing the same session, But between threads session Example of isolation
public class T24 {
/**
* session Variable definitions
*/
static ThreadLocal<Session> sessionThreadLocal = new ThreadLocal<>();
/**
* obtain session
*/
static Session getSession() {
if (null == sessionThreadLocal.get()) {
sessionThreadLocal.set(new Session());
}
return sessionThreadLocal.get();
}
/**
* remove session
*/
static void closeSession() {
sessionThreadLocal.remove();
}
/**
* Simulate a call session Methods
*/
static void fun1(Session session) {
}
/**
* Simulate a call session Methods
*/
static void fun2(Session session) {
}
public static void main(String[] args) {
new Thread(() -> {
fun1(getSession());
fun2(getSession());
closeSession();
}).start();
}
/**
* Simulate one session
*/
static class Session {
}
}

therefore ,ThreadLocal The most fundamental usage scenario should be :

When each thread wants to have a unique variable ( This variable also probably needs to be Shared within the same thread )
Avoid the need for each thread to actively create this object ( If you need to share , The problem of parameter passing back and forth is also solved )
In other words ,“ How to solve it gracefully : The problem of inter-thread isolation and intra-thread sharing ”, Not to solve messy thread safety problems
So if there are scenarios where you need thread isolation , Then consider ThreadLocal, Rather than what thread safety issue do you have to solve , And turn to ThreadLocal, It's not the same thing
Now that it can be Shared within threads , Naturally it can be used to pass global arguments within a thread , But don't abuse it
Again, pay attention to :
ThreadLocal Just the ability to do that , Is that you can do one unique variable per thread , But if you set when , Not transitive new The new variable that comes out , It just means “ A different reference for each thread ”, The object is the same object ( It's kind of like the value passing when the argument is passed , What is passed to an object is a reference )

Memory leak

ThreadLocal It solves the problem of thread data isolation very well , But obviously , It also introduces another space problem
If there are a lot of threads , If ThreadLocal There are many types of variables , It will take up a lot of space
And for ThreadLocal itself , He was simply key, The data is not stored inside it , So for ThreadLocal
ThreadLocalMap The inner one Entity Of key Is a weak reference
As shown in the figure below , Solid lines represent strong references , Dotted lines indicate weak references
For real values is stored in Thread Inside ThreadLocal.ThreadLocalMap threadLocals Medium
With the help of this inside one map, adopt “ shell ”ThreadLocal Variable get, You can get this map The true value of , in other words , Holds the true value in the current thread value A strong reference to
And for ThreadLocal Variable itself , As shown in the following code , The variable in the stack and the object in the heap space , It's also strongly referenced
  static ThreadLocal<String> threadLocal = new ThreadLocal<>();
But for the Entity Come on ,key Is a weak reference
When the sequence of execution is over ,ThreadLocal The strong reference of , This is the following between heap and stack ThreadLocal Ref To ThreadLocal The arrow will break
because Entity in , about key Is a weak reference , therefore ThreadLocal The variable will be recycled (GC Will recycle weak references )
For threads , If it takes too long to finish , Then there will always be :Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value A strong reference to , therefore value Delayed recovery , Memory leaks are possible  
ThreadLocalMap This situation has been taken into account in the design of , therefore ThreadLocal Of get(),set(),remove() Will clear the thread ThreadLocalMap In all key by null Of value
With get Methods as an example
Once the value Set to null after , It cuts off references between real memory , You can really free up space , Prevent memory leaks
But this is a passive way , What if none of these methods are called ?
And now for multithreading , Both use thread pools , That thread is likely to die with the application , What do I do ?
Then you use it every time ThreadLocal After a variable , perform remove Method !!!!
It can also be seen from the above analysis , because ThreadLocalMap The life cycle of Thread As long as , So memory leaks are likely , Weak references are an added protection
adopt key The weak references , as well as remove Built-in logic such as methods , By reasonable handling , Reduces the possibility of memory leaks , If not regulated , It still causes memory leaks

summary

ThreadLocal Can be used to elegantly resolve thread - isolated objects , Must actively create the problem , With the help of ThreadLocal There is no need to explicitly create objects in a thread , The solution is elegant
ThreadLocal Medium set The method does not guarantee that each thread will get a different object , You have to do something with the logic ( Like in the example above getSession Method , If ThreadLocal Variable get by null, that new object )
Can you really do thread isolation , It also depends on your own coding implementation , But if it's a Shared variable , Are you still in the ThreadLocal Why in the ?
So it's usually a thread-specific object , adopt new establish

In depth analysis of ThreadLocal Detailed explanation 、 Realization principle 、 Use scenario methods and memory leak prevention Multithreading II ( seventeen ) More articles about

  1. android Handler Mechanism ThreadLocal Detailed explanation

    summary We're talking about Handler When it comes to mechanisms , In fact, it's about Handler.Message.Looper.MessageQueue The relationship between , We will not elaborate on its working principle (Handler Detailed explanation of mechanism ). Messa ...

  2. JavaEE actual combat ——XML file DOM、SAX、STAX Detailed explanation of analytical methods

    primary JavaEE actual combat --XML file DOM.SAX.STAX Detailed explanation of analytical methods 2016 year 06 month 22 Japan 23:10:35 Li Chunchun _ Read the number :3445 label : DOMSAXSTAXJAXPXML Pull more ...

  3. HiveSQL The analysis process is explained in detail | Toddler Park

    HiveSQL The analysis process is explained in detail | Toddler Park   http://www.xuebuyuan.com/2210261.html

  4. Solr Series five :solr Search for details (solr Search process introduction 、 Query syntax and parser details )

    One .solr Search process introduction 1. We have learned before Lucene The search process , Let's review Process description : First, get the query string input by the user , Using the query parser QueryParser Parsing query string to generate query object Query ...

  5. ( turn )DNS The analysis process is explained in detail

    DNS The analysis process is explained in detail original text :http://blog.csdn.net/crazw/article/details/8986504 But first, let me say DNS Some basic concepts of : One . Root region It's called “.”, In fact, our ...

  6. DNS The analysis process is explained in detail ( Reprint )

    DNS The analysis process is explained in detail ( Reprint ) DNS Domain Name System The domain name system , It is based on the domain name to find out IP Address .    But first, let me say DNS Some basic concepts of : One . Root region It's called “.”, In fact, our website ww ...

  7. JAVA Four of them JSON Detailed explanation of analytical methods

    JAVA Four of them JSON Detailed explanation of analytical methods In our daily development, we have to work with JSON Dealing with data , So let's see JAVA Commonly used JSON Analytical way . 1.JSON official Use without framework 2.GSON 3.FastJSON ...

  8. # Okhttp analysis —Interceptor Detailed explanation

    Okhttp analysis -Interceptor Detailed explanation Interceptor Can be said to be okhttp One of the essence of ,Okhttp Rewrite request / Respond to . retry . Cache response and other operations , Basically, it's all in different areas Interceptor Done in , Part 1 ...

  9. Java Medium ThreadLocal Detailed explanation

    One .ThreadLocal brief introduction When multithreads access the same shared variable, it is easy to have concurrency problems , Especially when multiple threads write to a variable , To ensure thread safety , When users access shared variables, they need to take extra synchronization measures to ensure line synchronization ...

Random recommendation

  1. ( turn )sql server 2008 Saving changes is not allowed , Your changes require the following tables to be deleted and recreated Solutions for

    start-up SQL Server 2008 Management Studio Tools menu ---- Options ----Designers( Designer )---- Prevent saving changes that require the table to be recreated   Uncheck it .

  2. vs2008 The evaluation period of the trial version is over. Solutions

    1. Control panel ---- Procedures and functions ---- find VS2008, open " uninstall / change ". 2. Download the patch :files.cnblogs.com/elaky/PatchVS2008.zip Patch it ...

  3. .NET Use DAO.NET The entity class model operates on the database

    One . New projects open vs2017, Create a new project , Name it orm1 Two . New database open SqlServer database , New database orm1, And create a new table student . 3、 ... and . newly build ADO.NET Entity data model ...

  4. tomcat Release simple html Website

    1. Create a folder D:\Demo 2. stay Demo Under the table of contents , Build a WEB-INF And put web.xml Put it in there ,D:\Demo\WEB-INF\web.xml 3. take index.html Files in De ...

  5. redux And react-redux

    Redux One .Redux The three principles : 1. An application always has only one data source ( The whole application state is saved in one object ,Redux Tool functions provided combineReducers It can solve the problem of huge data objects ) 2. Status is ...

  6. Container cloud technology choice kubernetes and swarm contrast

    swarm and k8s It's all container choreography services in essence . They can abstract the underlying host , Then start the application with the constructed image , With a final docker Deploy to the host in the same way .   Which solution should we choose as our container cloud service ? I think k8 ...

  7. Mysql In the data Packet for query is too large The wrong solution

    Sometimes , The program is connecting mysql When operating on the database , The following error message will appear : Packet for query is too large (4230 > 1024). You can change th ...

  8. pl/sql Cracking method

    Reprint source :http://blog.csdn.net/oscar999/article/details/2123803 Open the registry in run The input regedit Delete 1.HKEY_CURRENT_USER/S ...

  9. (Alpha)Let&#39;s- Personal contribution points

    Alpha The individual contributions of each stage are as follows : (1201) Lin Yu 60 (1190) Kang Jiahua 55 (1194) Liu Yanxi 53 (1168) Qiu Dongmin 48 (1183) Ma Yaohua 42 (1222) Zhang Qidong 42

  10. MySQL: ON DUPLICATE KEY UPDATE usage

    This syntax can be used to judge whether a record exists before inserting it , If not, insert , Otherwise update , Very convenient , There is no need to implement two SQL INSERT INTO osc_visit_stats(stat_date,type,id,vi ...