This article was compiled by Colodoo (Paper Umbrella)

Jdk1.8.0_131

I’m sure most people are dumbfounded about ThreanLocal, because I didn’t know ThreanLocal existed until I was asked about it in an interview.

Here are some conclusive introductions for the interview questions:

  • ThreadLocal is a thread-local storage mechanism provided in Java that can be used to cache data within a thread, the line

Procedures can retrieve cached data at any time, in any method

  • ThreadLocal is implemented using a ThreadLocalMap. Each Thread object contains a ThreadLocalMap whose key is a ThreadLocal object. The Map value is the value to be cached
  • Using ThreadLocal in a thread pool can cause a memory leak, because when ThreadLocal is used up, the key, value, or Entry object should be reclaimed, but threads in the thread pool don’t. Thread objects are strongly referenced to ThreadLocalMap, and ThreadLocalMap is also strongly referenced to Entry objects. The thread is not recycled, and Entry objects are not recycled, resulting in memory leaks. The solution is to use ThreadLocal objects. Manually clear the Entry object by calling the remove method of ThreadLocal
  • The classic application of ThreadLocal is connection management (a thread holds a connection that can be passed between different methods, threads do not share the same connection).

I then explain these conclusions from a source code perspective.

set

java.lang.ThreadLocal#set

public void set(T value) {
    // Get the current thread
    Thread t = Thread.currentThread();
    // Get the thread-local storage object in the thread
    ThreadLocalMap map = getMap(t);
    // If so, set the value
    if(map ! =null)
        map.set(this, value);
    else
        // Create a local storage object if it does not exist and set the value
        createMap(t, value);
}
Copy the code
  • Get current thread
  • Gets a local storage object in the current thread
  • Sets the value to the local storage object of the current thread

As you can see from this, ThreadLocal is scoped to the currentThread, and different threads are isolated from each other.

set

java.lang.ThreadLocal.ThreadLocalMap#set

private void set(ThreadLocal
        key, Object value) {

    // The Entry array is assigned to the temporary variable TAB
    Entry[] tab = table;
    // Get the length of the Entry array
    int len = tab.length;
    // Get the subscript using the hash algorithm based on the key
    int i = key.threadLocalHashCode & (len-1);

    // Iterate over the Entry array
    for(Entry e = tab[i]; e ! =null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<? > k = e.get();// Update if present
        if (k == key) {
            e.value = value;
            return;
        }

       	// Replace stale entries
        // TODO: The logic here is complex
        if (k == null) {
            replaceStaleEntry(key, value, i);
            return; }}// Otherwise, a new node is added
    tab[i] = new Entry(key, value);
    int sz = ++size;
    if(! cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }Copy the code

getMap

java.lang.ThreadLocal#getMap

ThreadLocalMap getMap(Thread t) {
    // Get the ThreadLocalMap in the thread
	return t.threadLocals;
}
Copy the code

createMap

java.lang.ThreadLocal#createMap

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
Copy the code

ThreadLocalMap

java.lang.ThreadLocal.ThreadLocalMap#ThreadLocalMap(java.lang.ThreadLocal<? >, java.lang.Object)

ThreadLocalMap(ThreadLocal<? > firstKey, Object firstValue) {// Instantiate the Entry array
    table = new Entry[INITIAL_CAPACITY];
    // Compute the subscript
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    // Add node to array
    table[i] = new Entry(firstKey, firstValue);
    // Set size =1
    size = 1;
    // Set the threshold
    setThreshold(INITIAL_CAPACITY);
}
Copy the code

get

java.lang.ThreadLocal#get

public T get(a) {
    // Get the current thread
    Thread t = Thread.currentThread();
    // Get the current thread ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    If ThreadLocalMap is not empty
    if(map ! =null) {
        / / for Entry
        ThreadLocalMap.Entry e = map.getEntry(this);
        // Get the result is not empty, return the result
        if(e ! =null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            returnresult; }}// Otherwise set the initialization value
    return setInitialValue();
}
Copy the code

The illustration

Here’s a picture to help you remember.