Java Concurrency series of six: in-depth understanding of ThreadLocal

introduction

Regardless of the actual project combat or an interview, ThreadLocalis not open around the topic, this paper from the perspective of the source and everyone to discuss the next ThreadLocalmystery.

  • ThreadLocalWhat is? It can do?
  • ThreadLocalSource code analysis
  • to sum up

First, ThreadLocalwhat is? It can do?

ThreadLocal Is a thread local variable, which means that variables are thread-exclusive, is not shared with other threads, it does not solve the problem of multi-threaded shared variables.

So ThreadLocalwith different thread synchronization mechanism, thread synchronization mechanisms are multiple threads share the same variable, and ThreadLocalevery thread create a separate copy of the variable is, therefore each thread can be changed independently variable copy what they have, rather than It will affect other threads corresponding copy. It can be said ThreadLocalis a multi-threaded environment variable provides an alternative solution ideas.

ThreadLocalThe idea is to use space for time, so that each thread can access their own a copy of this variable, the variable values ​​do not interfere with each other, reducing the complexity of some public functions or variables across multiple components within the same thread pass.

Here Insert Picture Description


Second, ThreadLocalsource code analysis

1, ThreadLocalMapparsing
ThreadLocal defined inside an ThreadLocalMapinner class, ThreadLocalMapthe actual use Entryto achieve key-valuestorage, as follows:

static class ThreadLocalMap {
	static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        ...
}

ThreadLocalMapIs the key thread isolation mechanism, can be seen from the above code Entryis keythat ThreadLocal, while valuethat value. At the same time, Entryalso inherited WeakReference, so that the Entrycorresponding key( ThreadLocalreference example) as a weak reference.

We mainly look at the core getEntry(), set(ThreadLocal> key, Object value)the method

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);
        }
 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            // 根据 ThreadLocal 的散列值,查找对应元素在数组中的位置
            int i = key.threadLocalHashCode & (len-1);

			// 采用“线性探测法”,寻找合适位置
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
				// 若key 存在,直接覆盖
                if (k == key) {
                    e.value = value;
                    return;
                }
				// key == null,但是存在值(因为此处的e != null),说明之前的ThreadLocal对象已经被回收了
                if (k == null) {
                	// 用新元素替换陈旧的元素
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
			//创建新元素
            tab[i] = new Entry(key, value);
            int sz = ++size;
            // 如果没有清理陈旧的 Entry 并且数组中的元素大于了阈值,则进行 rehash
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

2, the core analytical method
(1) get ()
value of the current thread to return a copy of this thread-local in

public T get() {
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的成员变量 threadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        	// 从当前线程的ThreadLocalMap获取相对应的Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                // 获取目标值
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

First, get through the current thread corresponding member variables ThreadLocalMap, and then ThreadLocalMapget the current ThreadLocalof Entrythe last acquisition target by Entry acquired result.

(2) set (T value)
of this value for the current thread in the thread-local variable copy of the specified value.

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

Get the current thread corresponding to ThreadLocalMap, if not empty, then call ThreadLocalMapthe set()method, key is present ThreadLocal, and if not, then call the createMap()method to create a new.

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

(3) initialValue ()
Returns the current thread is the initial value of this thread-local variable.

protected T initialValue() {
        return null;
    }

This method is defined as the protectedlevel and returns null, need to subclass perform its function, so we use ThreadLocalgenerally should override this method time. This method does not show the call, only the first call get()or set()will be executed when the method, and only performed once.

(4) remove ()
remove the current thread's value for this thread-local variable.

 public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

Third, the summary

1, when multiple threads to acquire a shared variable, the requirements to obtain a copy of the initial value of this variable. A copy of each thread to store this variable, change this variable does not affect copies of the variable itself. For multiple threads to complete the operation dependent variable values ​​of different scenes. such as:

  • Switching multiple data sources
  • spring declarative transaction

2, will be ThreadLocalprovided private static, so ThreadLocalwill try and recovered together with the thread itself.

Published 86 original articles · won praise 45 · views 80000 +

Guess you like

Origin blog.csdn.net/Diamond_Tao/article/details/103865434