java多線程-ThreadLocal


大綱:

  1. 用法
  2. 源碼

 

一、用法

ThreadLocal是一個容器,顧名思義就是把一個變量存到線程本地。

class Test {
    public static void main(String[] args)  {
        new Thread(new TestLocal()).start();
        new Thread(new TestLocal()).start();
        new Thread(new TestLocal()).start();
    }
}

class TestLocal implements Runnable {
    ThreadLocal<String> localName = new ThreadLocal<>();

    @Override
    public void run() {
        localName.set(Thread.currentThread().getName());
        System.out.println(localName.get());
    }
}

/**結果:
 * Thread-0
 * Thread-1
 * Thread-2
 */

 

 

二、源碼

ThreadLocal是線程本地變量,因此每個Thread對象內部必然存儲ThreadLocal,ThreadLocal作為key,存儲在ThreadLocalMap中。

class Thread {
    ThreadLocal.ThreadLocalMap threadLocals = null; //每個線程對象內部維護了一個ThreadLocal.ThreadLocalMap。
    ...
}

ThreadLocal主要方法就是set,get

  • set:
public class ThreadLocal<T> {

    static class ThreadLocalMap {...} //ThreadLocalMap是ThreadLocal的靜態內部類
    ...

    public void set(T value) {
        Thread t = Thread.currentThread(); //拿到當前線程
        ThreadLocalMap map = getMap(t); //取出線程維護的ThreadLocalMap
        if (map != null)
            map.set(this, value); //ThreadLocalMap的key為當前ThreadLocal對象,value就是我們需要存儲的變量
        else
            createMap(t, value); //該線程第一次使用ThreadLocal.set時創建ThreadLocalMap對象,並賦值。
    }

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

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

  ... }
  • get:
public class ThreadLocal<T> {

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); //從當前線程取出ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); //以當前ThreadLocal對象為key取出ThreadLocalMap.Entry
            if (e != null) {
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue(); //如果這個ThreadLocal對象沒有賦值直接get,會給它賦值為null並返回。
    }

    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;
    }

    protected T initialValue() {
        return null;
    }

  ... }

ThreadLocal get、set思想小結:

  1. 拿到當前線程對象。
  2. 拿到線程對象內部維護的ThreadLocalMap對象。
  3. 一個線程對象中只有一個ThreadLocalMap對象,所有ThreadLocal對象及這個ThreadLocal對象存儲的值都以key-value的形式存在ThreadLocalMap中。(ThreadLocalMap的key是ThreadLocal對象,value是需要存儲的變量。)

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM