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

What is the principle and usage of FastThreadLocal in Netty

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

Share

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

This article introduces the principle and usage of Netty FastThreadLocal. The content is very detailed. Interested friends can use it for reference. I hope it will be helpful to you.

What is Netty's FastThreadLocal?

In short, FastThreadLocal is a variant of ThreadLocal implementation. Compared with ThreadLocal, which locates the required variable storage location on hashTable by hash itself, FastThreadLocal chooses a fixed constant location on the array to store thread-local variables. This operation does not seem to be much different, but it does show a performance advantage over ThreadLocal, especially in the scenario of frequent read operations.

How to use FastThreadLocal

If you want to get the speed advantage of FastThreadLocal, you can only use it through threads of FastThreadLocalThread or its subclasses. For this reason, the newThread () method of Netty's DefaultThreadFactory, its internal default thread factory, is to initialize a FastThreadLocalThread directly in order to expect its performance advantage in the operation of ThreadLocal.

Protected Thread newThread (Runnable r, String name) {return new FastThreadLocalThread (threadGroup, r, name);} the source code of FastThreadLocal implements the entry to which FastThreadLocal is accessed

When you need to use FastThreadLocal, it must be similar to the api of jdk's native ThreadLocal, which initializes a new FastThreadLocal, initializes it through its set () method, and stores a variable as a thread-local variable.

Public final void set (V value) {if (value! = InternalThreadLocalMap.UNSET) {set (InternalThreadLocalMap.get (), value);} else {remove ();}}

Therefore, in the set () method of FastThreadLocal, you can see that the data structure that stores local thread variables is an InternalThreadLocalMap.

Private InternalThreadLocalMap threadLocalMap

In FastThreadLocalThread, because threadLocalMap itself is a member, it can be returned quickly. Other thread implementations will face the embarrassment of not having this member, and Netty provides compatibility accordingly.

Public static InternalThreadLocalMap get () {Thread thread = Thread.currentThread (); if (thread instanceof FastThreadLocalThread) {return fastGet ((FastThreadLocalThread) thread);} else {return slowGet ();}}

In the get () method of InternalThreadLocalMap, if the current thread is an implementation of FastThreadLocalThread or its subclass, it returns its InternalThreadLocalMap directly for operation, but for threads that do not belong to the above condition, Netty will also return an InternalThreadLocalMap through slowGet ().

Private static InternalThreadLocalMap slowGet () {ThreadLocal slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap; InternalThreadLocalMap ret = slowThreadLocalMap.get (); if (ret = = null) {ret = new InternalThreadLocalMap (); slowThreadLocalMap.set (ret);} return ret;}

In the slowGet () method, the InternalThreadLocalMap corresponding to the current thread is stored as ThreadLocal under the native jdk and returned through ThreadLocal. Therefore, in this scenario, the native ThreadLocal of jdk is still used, but only one location of the Entry [] array under the native ThreadLocal is occupied, and the specific variables are still stored in the InternalThreadLocalMap that serves FastThreadLocal.

Here, as the InternalThreadLocalMap is obtained and returned, the get and set operations for FastThreadLocal will also be changed to operate InternalThreadLocalMap to achieve the goal, and the reason for the superior performance of FastThreadLocal is also in InternalThreadLocalMap.

The internal structure of InternalThreadLocalMap static final AtomicInteger nextIndex = new AtomicInteger (); Object [] indexedVariables

InternalThreadlocalMap is mainly composed of the above two members. IndexedVariables, as an Object [] array, is directly used to store the value corresponding to FastThreadLocal. Each FastThreadLocal object is assigned to the corresponding index in the ThreadLocalMap of the corresponding thread, and the specific subscript here is assigned by the above nextIndex members when each FastThreadLocal is initialized.

Private final int index;public FastThreadLocal () {index = InternalThreadLocalMap.nextVariableIndex ();}

During the construction of a method, each FastThreadLocal returns the result of the nextIndex addition through InternalThreadlocalMap's nextVariableIndex () as its subscript on the InternalThreadlocalMap. The subsequent FastThreadLocal can directly navigate to the location on the Object [] array through the index when manipulating variables.

Private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex ()

The subscript on the array has a special bit, usually in its first position, which is 0, which is set as a static variable when the FastThreadLocal class is loaded. In this location, a collection of FastThreadLocal objects is stored, and each FastThreadLocal stored in InternalThreadlocalMap is stored in the first collection.

Public static final Object UNSET = new Object ()

In addition, in order to specifically distinguish whether the saved variable is null or there is no current variable, a member variable called NULL is defined in InternalThreadLocalMap to distinguish the above situation. In the beginning, the indexedVariables array in InternalThreadLocalMap is NULL.

Source code analysis of set () method of FastThreadLocal

Compared with the set operation of FastThreadLocal, the process and logic of the get method are much simpler, so the set method is mainly used here.

Public final void set (V value) {if (value! = InternalThreadLocalMap.UNSET) {set (InternalThreadLocalMap.get (), value);} else {remove ();}} public final void set (InternalThreadLocalMap threadLocalMap, V value) {if (value! = InternalThreadLocalMap.UNSET) {if (threadLocalMap.setIndexedVariable (index, value)) {addToVariablesToRemove (threadLocalMap, this);}} else {remove (threadLocalMap) }}

In its set () method, it will first determine whether the value of set is a NULL object in InternalThreadLocalMap to determine whether it is a set operation or a remove operation. If not, it will get the corresponding InternalThreadLocalMap of the current thread through the InternalThreadLocalMap.get () method, which has been described earlier. The main process after that is mainly divided into two steps:

Call the setIndexedVariable () method of InternalThreadLocalMap, passing in the subscript on the InternalThreadLocalMap obtained by the FastThreadLocal member in the constructor as an input parameter.

Public boolean setIndexedVariable (int index, Object value) {Object [] lookup = indexedVariables; if (index < lookup.length) {Object oldValue = lookup [index]; lookup [index] = value; return oldValue = = UNSET;} else {expandIndexedVariableTableAndSet (index, value); return true;}}

In the setIndexedVariable () method of InternalThreadLocalMap, the process of set is not complicated. Find the corresponding subscript and put the corresponding value on the corresponding position of the subscript of the InternalThreadLocalMap array. However, although FastThreadLocal has obtained the corresponding subscript in advance during the construction process, the actual array size may not have reached the corresponding size at all, so you need to expand the capacity here through the expandIndexedVariableTableAndSet () method. Because it is an array, you only need to copy the original value after expansion and fill the remaining values with the NULL object.

If set is successful in the previous step, the FastThreadLocal object is placed in the first collection in the array of InternalThreadLocalMap through the addToVariablesToRemove () method. In this collection, it is a strong reference to FastThreadLocal.

In this way, a set operation on FastThreadLocal ends.

Where on earth is FastThreadLocal fast? Fast positioning

In the specific positioning process of FastThreadLocal, you only need to locate the specific array location to access variables according to the specific subscript obtained in the construction method, while in the native ThreadLocal of jdk, the subscript acquisition of specific location not only needs to calculate the hash value of ThreadLocal, but also needs to locate on hashTable according to the result of key positioning. Once other ThreadLocal variables already exist on the positioning result, then it is through linear detection. The process of finding the next location on hashTable is much more complicated than that of FastThreadLocal.

two。 Expansion is simple

Because FastThreadLocal adopts the method of array, when face-to-face expansion, you only need to copy the contents of the original array and fill the remaining positions with NULL objects. In ThreadLocal, due to hashTable, a round of rehash is needed after expansion. In this process, there is still the possibility of hash conflicts.

3. Low-overhead memory leak detection

In FastThreadLocal, traversing all the local variables of the current thread only needs to take the collection of the first bit of the array, rather than traversing every location on the array.

In native ThreadLocal, due to the possibility that ThreadLocal is reclaimed, but the current thread is still alive, the memory leak of the local variable corresponding to ThreadLocal is leaked, so heuristic memory leak detection is carried out after each operation of ThreadLocal to prevent this problem, but it also costs extra overhead after each operation.

In the FastThreadLocal scenario, because all references to FastThreadLocal objects are held in the FastThreadLocal collection at the top of the array, when the reference to the external FastThreadLocal is set to null, the FastThreadLocal object still maintains the reference to the collection and will not be recycled. It only needs to manually call the removeAll () method of FastThreadLocal after the thread's current business operation, which will traverse the first collection of the array and recycle all FastThreadLocal variables to avoid memory leaks. It also reduces the heuristic detection overhead of native ThreadLocal.

Private static final class DefaultRunnableDecorator implements Runnable {private final Runnable r; DefaultRunnableDecorator (Runnable r) {this.r = r;} @ Override public void run () {try {r.run ();} finally {FastThreadLocal.removeAll ();}

In Netty's DefaultThreadFactory, each thread calls the removeAll () method of FastThreadLocal after executing as a task.

About the principle and usage of Netty FastThreadLocal is shared here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

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