In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly explains the "java programming ThreadLocal up and down transfer source code analysis", the content of the article is simple and clear, easy to learn and understand, the following please follow the editor's ideas slowly in depth, together to study and learn "java programming ThreadLocal up and down transfer source code analysis" bar!
Introduction language
ThreadLocal provides a way for each thread to have its own unique data in a multithreaded environment and can be passed from top to bottom throughout thread execution.
1. Demonstration of usage
Many students may not have used ThreadLocal. Let's demonstrate the use of ThreadLocal first. Demo is as follows:
/ * the data stored in ThreadLocal is Map * / static final ThreadLocal context = new ThreadLocal (); @ Testpublic void testThread () {/ / take Map Map contextMap = context.get (); if (CollectionUtils.isEmpty (contextMap)) {contextMap = Maps.newHashMap ();} contextMap.put ("key1", "value1"); context.set (contextMap); log.info ("key1,value1 is put in context") / / take the data just put in getFromComtext () from the context;} private String getFromComtext () {String value1 = context.get (). Get ("key1"); log.info ("take the context from ThreadLocal, the corresponding value of key1 is: {}", value1); return value1 } / / run result: demo.ninth.ThreadLocalDemo-key1,value1 is put into context demo.ninth.ThreadLocalDemo-context is extracted from ThreadLocal, and the corresponding value of key1 is: value1
As you can see from the run result, the corresponding value of key1 has been taken from the context.
The getFromComtext method does not accept any input parameters, and the line of code context.get (). Get ("key1") gets the value of key1 from the context. Let's take a look at how the underlying ThreadLocal implements context passing.
2. Class structure 2.1, class generics
ThreadLocal defines classes with generics, indicating that ThreadLocal can store data in any format. The source codes are as follows:
Public class ThreadLocal {} 2.2, key attributes
ThreadLocal has several key attributes, let's take a look at them one by one:
/ / threadLocalHashCode represents the hashCode of the current ThreadLocal, which is used to calculate the index position of the current ThreadLocal in ThreadLocalMap private final int threadLocalHashCode = nextHashCode (); / / calculate the hashCode value of ThreadLocal (that is, increment) private static int nextHashCode () {return nextHashCode.getAndAdd (HASH_INCREMENT) } / / static + AtomicInteger ensures that the threadLocalHashCode of each ThreadLocal in a machine is unique / / it is critical to be modified by static, because a thread in the process of processing business, ThreadLocalMap will be set multiple ThreadLocal, multiple ThreadLocal will rely on threadLocalHashCode to distinguish private static AtomicInteger nextHashCode = new AtomicInteger ()
There is another important attribute: ThreadLocalMap. When a thread has more than one ThreadLocal, you need a container to manage multiple ThreadLocal,ThreadLocalMap. This is what manages multiple ThreadLocal in a thread.
2.2.1 、 ThreadLocalMap
ThreadLocalMap itself is a simple Map structure. Key is the value saved by ThreadLocal,value and ThreadLocal. The underlying data structure is the array. The source code is as follows:
/ / threadLocalHashCode represents the hashCode of the current ThreadLocal, which is used to calculate the index position of the current ThreadLocal in ThreadLocalMap private final int threadLocalHashCode = nextHashCode (); / / calculate the hashCode value of ThreadLocal (that is, increment) private static int nextHashCode () {return nextHashCode.getAndAdd (HASH_INCREMENT) } / / static + AtomicInteger ensures that the threadLocalHashCode of each ThreadLocal in a machine is unique / / it is critical to be modified by static, because a thread in the process of processing business, ThreadLocalMap will be set multiple ThreadLocal, multiple ThreadLocal will rely on threadLocalHashCode to distinguish private static AtomicInteger nextHashCode = new AtomicInteger ()
You can see from the source code that ThreadLocalMap is actually a simple Map structure. The underlying layer is an array, with initialization size and expansion threshold size. The element of the array is the key of Entry,Entry, which is a reference to ThreadLocal, and value is the value of ThreadLocal.
3. How does ThreadLocal achieve data isolation between threads
ThreadLocal is thread-safe and we can rest assured to use it, mainly because ThreadLocalMap is an attribute of the thread. Let's take a look at the source code of the thread Thread, as follows:
From the figure above, we can see that ThreadLocals.ThreadLocalMap and InheritableThreadLocals.ThreadLocalMap are respectively thread properties, so the ThreadLocals of each thread is isolated and exclusive.
When the parent thread creates a child thread, it copies the value of inheritableThreadLocals, but not the value of threadLocals. The source code is as follows:
As we can see from the figure above, the inheritableThreadLocals attribute value of the parent thread is copied when the thread is created.
4. Set method
The main function of the set method is to set the value in the current ThreadLocal. If the generic type of the current ThreadLocal is Map, it is to set map the current ThreadLocal. The source code is as follows:
/ / set operation each thread is serial, there will be no thread safety problems public void set (T value) {Thread t = Thread.currentThread (); ThreadLocalMap map = getMap (t); / / there is a setting before the current thradLocal, which is directly set, otherwise initialize if (map! = null) map.set (this, value); / / initialize ThreadLocalMap else createMap (t, value);}
The logic of the code is relatively clear. Let's take a look at the source code of ThreadLocalMap.set, as follows:
Private void set (ThreadLocal key, Object value) {Entry [] tab = table; int len = tab.length; / / calculates the subscript of key in the array, which is actually the hashCode of ThreadLocal and the size of the array-1 minus int I = key.threadLocalHashCode & (len-1) / / overall strategy: check whether the index location has a value, and if so, the index location is + 1 until the location with no value is found. / / this strategy for resolving hash conflicts also leads to different search strategies in get, as reflected in for (Entry e = tab [I]; e! = null) in getEntryAfterMiss. / / nextIndex means that on the basis of not exceeding the length of the array, the index position of the array + 1 e = tab [I = nextIndex (I, len)]) {ThreadLocal k = e.get (); / / find the ThreadLocal with the same memory address, and directly replace if (k = = key) {e.value = value; return } / / the current key is null, which means that ThreadLocal has been cleaned up and if (k = = null) {replaceStaleEntry (key, value, I) {replaceStaleEntry (key, value, I); return;}} / / the current I position is worthless and can be used by the current thradLocal as tab [I] = new Entry (key, value); int sz = + + size / / expand if (! cleanSomeSlots (I, sz) & & sz > = threshold) rehash () when the array size is greater than or equal to the expansion threshold (2/3 of the array size);}
We pay attention to the following points of the above source code:
Is used as the hashCode of ThreadLocal through the increment of AtomicInteger
The formula for calculating the index position of the array is: hashCode takes the size of the modular array. Because hashCode continues to increase, different hashCode will be calculated to the index position of the same array in high probability (but don't worry about this, in the actual project, ThreadLocal is very few, basically will not conflict)
If there is already a value at the index position I calculated by hashCode, it will start from I and keep looking back through + 1 until you find the empty index position and put the current ThreadLocal as a key.
Fortunately, when using ThreadLocal in daily work, only 1 or 2 ThreadLocal are often used, and the probability of calculating repeated arrays through hash is not very high.
Set's strategy for resolving array element position conflicts also has an impact on the get method, so let's take a look at the get method.
5. Get method
The get method mainly obtains the value stored in the current ThreadLocal from ThreadLocalMap. The source code is as follows:
Public T get () {/ / because threadLocal belongs to the attribute of the thread, you need to first take out the current thread Thread t = Thread.currentThread (); / / get ThreadLocalMap ThreadLocalMap map = getMap (t) from the thread If (map! = null) {/ / get entry from map. The logic of ThreadLocalMap.Entry e = map.getEntry (this) is different due to the different strategy of hash conflict in set. / / if it is not empty, read the value if (e! = null) {@ SuppressWarnings ("unchecked") T result = (T) e.value saved in the current ThreadLocal; return result;}} / otherwise initialize the ThreadLocal of the current thread and return the initial value null return setInitialValue ();}
Next, let's take a look at ThreadLocalMap's getEntry method. The source code is as follows:
/ / get the corresponding value of the current thradLocal. The type of the value is determined by the generics of thradLocal / / because the logic of solving the conflict of array index position in thradLocalMap set leads to the corresponding logic of thradLocalMap get. / / first try to find the size of the modular array-1 = index position I according to hashcode. If you can't find it, spin iDiff1. Until it is found that the index location is not empty, private Entry getEntry (ThreadLocal key) {/ / calculate the index location: hashCode of ThreadLocal takes module array size-1 int I = key.threadLocalHashCode & (table.length-1) Entry e = table [I]; / e is not empty, and the memory address of e's ThreadLocal is the same as key, return directly, otherwise it will not be found. The logic of continuing to find if (e! = null & & e.get () = key) return e; else / / this data fetching logic is due to return getEntryAfterMiss (key, I, e) caused by set array index position conflict. } / / spin iTunes 1 until private Entry getEntryAfterMiss (ThreadLocal key, int I, Entry e) {Entry [] tab = table; int len = tab.length; / / when using a lot of ThreadLocal of different key, while (e! = null) {ThreadLocal k = e.get () / / memory address is the same, which means if (k = = key) return e has been found; / / useless key if (k = = null) expungeStaleEntry (I) has been deleted; / / continue to make index position + 1 else I = nextIndex (I, len); e = tab [I];} return null;}
The comments in the get logical source code have been written very clearly, so we won't repeat them.
6. Capacity expansion
When the number of ThreadLocal in ThreadLocalMap exceeds the threshold, ThreadLocalMap will begin to expand. Let's take a look at the logic of capacity expansion:
/ / expand private void resize () {/ / take out the old array Entry [] oldTab = table; int oldLen = oldTab.length; / / the new array is twice the size of the old array int newLen = oldLen * 2; / / initialize the new array Entry [] newTab = new Entry [newLen]; int count = 0; / / copy the value of the old array to the new array for (int j = 0; j < oldLen) + + j) {Entry e = oldTab [j]; if (e! = null) {ThreadLocal k = e.get (); if (k = = null) {e.value = null; / / Help the GC} else {/ / calculate the position of ThreadLocal in the new array int h = k.threadLocalHashCode & (newLen-1) / / if the position value of index h is not empty, then + 1 until the index position while (newTab [h]! = null) h = nextIndex (h, newLen) is found; / / assign the value newTab [h] = e to the new array; count++ Initialize the next expansion threshold for the new array, which is 2/3 setThreshold (newLen) of the array length; size = count; table = newTab;}
The source code comments are also relatively clear, let's pay attention to two points:
After expansion, the size of the array is twice that of the original array.
There is absolutely no thread safety problem when expanding capacity, because ThreadLocalMap is an attribute of a thread, a thread can only operate on ThreadLocalMap at the same time, because the same thread executes business logic must be serial, then the operation ThreadLocalMap must also be serial.
Thank you for your reading, the above is the content of "java programming ThreadLocal up and down transfer source code analysis". After the study of this article, I believe you have a deeper understanding of the problem of java programming ThreadLocal up and down transfer source code analysis, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.