Reprint Please specify the Source:http://blog.csdn.net/jevonscsdn/article/details/54353177 "Jevons ' blog"
the purpose and function of threadlocal:
Used to implement data sharing within a thread, that is, for the same program code, multiple modules share one piece of data while running in the same thread, while another data is shared while running in another thread.
Each thread invokes the set method of the global Threadlocal object, which is equivalent to adding a record to its internal map, and the key is the Threadlocal object, and value is the values that the respective threads pass through the set method. At the end of a thread, you can call the Threadlocal.clear () method, which frees up memory faster (not required, because the associated threadlocal variable can be automatically released after the thread ends).
When we need to use a thread-local variable, we often think of the threadlocal class, and each thread maintains a threadlocal.threadlocalmap mapping table:
public class Thread implements Runnable {
...
/* ThreadLocal values pertaining to this thread. This map was maintained
* by the ThreadLocal class. *
/Threadlocal.threadlocalmap threadlocals= null;
...
}
Here we have the initialization process of holding variable threadlocals through source code analysis thread.
Let's take a look at the initialization method:
public class Threadlocal<t> {
...
void Createmap (Thread T, T firstvalue) {
t.threadlocals = new Threadlocalmap (this, firstvalue);
...
}
You can see that the Createmap (thread T, t firstvalue) method initializes the threadlocals in the thread class.
And then trace the Threadlocalmap construction method source code:
Threadlocalmap (ThreadLocal Firstkey, Object firstvalue) {
table = new Entry[initial_capacity];
int i = Firstkey.threadlocalhashcode & (initial_capacity-1);
Table[i] = new Entry (Firstkey, firstvalue);
size = 1;
Setthreshold (initial_capacity);
}
Size:the number of entries in the table. That is the quantity of the entry in the table;
Setthreshold (int len): Set The resize threshold to maintain at worst a
2/3 load factor. Len setting the capacity adjustment threshold to 2/3;
You can see that the constructed method initializes the initial capacity of the entry[] table:
private static final int initial_capacity = 16;
Get the index through the Firstkey.threadlocalhashcode & (initial_capacity-1) operation, and then a new entry (Firstkey, firstvalue), The entry inherits the Weakreference<threadlocal> class, stating that the key it holds is a weak reference to ThreadLocal. Let's look at the source code:
Static class Threadlocalmap {
...
The static class Entry extends Weakreference<threadlocal> {
/** the value associated with this ThreadLocal. */
O Bject value;
Entry (ThreadLocal K, Object v) {
super (k);
Value = V;
}
}
...
}
You can see that the construction of the parent class is invoked in the constructor and the key is passed in, and then traced down to the WeakReference class:
public class Weakreference<t> extends reference<t> {
/**
* Creates a new weak Reference The given object. The new
* Reference is isn't registered with any queue.
*
* @param referent Object The new weak reference'll refer to
*
/Public weakreference (T referent) {
Supe R (referent);
}
...
}
Further down:
Public abstract class Reference<t> {
...
/*-Constructors-*/
Reference (T referent) {This
(referent, null);
}
Reference (T referent, referencequeue< Super t> queue) {
this.referent = referent;
This.queue = (queue = null)? ReferenceQueue.NULL:queue;
}
...
}
Here the Reference (T referent) calls the Reference (t referent, referencequeue< super t> queue) and passes in threadlocal as key, which is critical here. As we go through Threadlocal's Get () method, he is the key to judging whether the key is the same. That this referent is what dongdong, the source code is its annotation:
/* Treated specially by GC * *
GC treats objects specifically. This is a GC-time reference, the weak reference here is not introduced in detail, the self google~
Well, the pit dug a bit deep, now back, then Threadlocal class in the Createmap (Thread T, T firstvalue) method is called by WHO.
There are two ways to invoke it in threadlocal:
1.set (T)
2. T Setinitialvalue () set (t) source code:
public void Set (t value) {
Thread t = thread.currentthread ();
Threadlocalmap map = getmap (t);
if (map!= null)
Map.set (this, value);
else
createmap (t, value);
As you can see, the method first passes the Thread.CurrentThread (), gets the current thread, plugs it into getmap (t) to get a threadlocalmap return value, and the following is the source code for GETMAP ():
Threadlocalmap Getmap (Thread t) {return
t.threadlocals;
}
Simply and rudely returns the Thredlocals directly, then makes the judgment, if the map is empty (does not say for empty), call the Createmap (T, value) method, pass the current thread and the thread local variable value that needs to be set into, and the Threadlocals Initialization operation. Setinitialvalue () Source:
Private T Setinitialvalue () {
T value = InitialValue ();
Thread t = thread.currentthread ();
Threadlocalmap map = getmap (t);
if (map!= null)
Map.set (this, value);
else
createmap (t, value);
return value;
}
Bingo! the same trick.
What if I didn't set the value first but direct get (). Get () source code:
Public T get () {
Thread t = thread.currentthread ();
Threadlocalmap map = getmap (t);
if (map!= null) {
Threadlocalmap.entry e = Map.getentry (this);
if (e!= null) return
(T) e.value;
}
return Setinitialvalue ();
}
Because I do not set the value, so the map is empty, directly callback Setinitialvalue ();
The above is the initialization process for the THREADLOCAL.THREADLOCALMAP mapping table, and the threadlocal get () method operation is described below.
Then the Threadlocal object is passed as a key by Map.getentry (this) if the value is set beforehand and the map is not empty. The source code of the Threadlocalmap Getentry method:
/** * Get the entry with key. This method * itself handles only the fast path:a direct hit of existing * key. It otherwise relays to Getentryaftermiss. This are * designed to maximize performance for direct hits, in part * by making this method readily Inli
Nable.
* @param key The thread local object * @return the entry associated with key, or null if no such * Private Entry Getentry (ThreadLocal key) {int i = Key.threadlocalhashcode & (table.length
-1);
Entry e = table[i];
if (e!= null && e.get () = = key) return e;
else return Getentryaftermiss (key, I, E); }
The index I of the entry is obtained first through the Key.threadlocalhashcode & (table.length-1) operation, then the entry E is judged by the table[i], and if E is not null, the E.get () Take out entry inside the key and the incoming key comparison, if equal, directly return E, otherwise callback Getentryaftermiss (key, I, E).
Let's take a look at this e.get () Source:
/**
* Returns This Reference object ' s referent. If This is reference object has
* been cleared, either by the "program" or by the garbage collector, then
* returns <CODE>NULL</CODE>
*
* @return the object to which this reference refers, or
* <code>null</code> if this Referen Ce object has been cleared
*
/public T get () {return
this.referent;
}
Again this referent, so coincidence again, with broken English translation, the meaning of source code annotation is:
Returns a reference to this reference object that returns a null value if the reference object has been purged by the program or the garbage collector.
@return A reference to this Application object, and returns a null value if the reference object has been cleared.
So, this referent got is the key that was originally set in, here again through E.get () take out as comparison condition. Said the above condition is not tenable then callback function Getentryaftermiss (key, I, E), under what circumstances will cause the condition to be not tenable. Continue tracking Source:
/** * Version of Getentry method to use the When
key isn't found in
* Its direct hash slot.
*
@param Key The thread local object
* @param i the table index for key ' s hash code
* @param e t He entry at Table[i]
* @return The entry associated with key, or null if no such
* *
Private entry Getentrya Ftermiss (ThreadLocal key, int i, Entry e) {
entry[] tab = table;
int len = tab.length;
while (e!= null) {
ThreadLocal k = E.get ();
if (k = = key) return
E;
if (k = = null)
expungestaleentry (i);
else
i = Nextindex (i, Len);
e = Tab[i];
}
return null;
}
Let's take a look at the source code comments:
*version of Getentry method of??
Direct hash slot.
Meaning is used when the key can not be obtained through the direct hash of the solution, under what circumstances will lose key. Here are three points of judgment, the first one goes without saying, and the second we say, as for the third, let's take a look at the interpretation of the I parameter in the source code:
@param i the table index for key ' s hash code is used to get the hash code of the key
So it's not hard to guess, the position is wrong, through Nextindex (i, Len) for the next index trace.
Let's talk about the second case, before we also said that entry key is a weak reference to threadlocal, and weak reference is easier to be collected by GC, how easy. The next GC work will take him back, so there will be entry inside the key is empty null situation, obviously others also help you consider these things, so in order to prevent memory leaks, when the recognition of the key is NULL, it will call Expungestaleentry (i) Get rid of the entry.