java-ThradLocal-源碼分析-爲什麼這樣設計

源碼分析

  • 需要注意的是這裏只是分析ThreadLocal的源碼,不會介入Thread的源碼分析,雖然他們息息相關

使用

  • 一般使用的時候都是封裝成一個工具來使用,在這個地方存,在其他地方調用,切記用完要刪除!!!
public class ThreadLocalUtils {
    private final static ThreadLocal<User> local;
	get/set/delete...
}

疑問

  • 首先我們要有一個疑問,ThreadLocal 是怎麼做到從這裏存,在其他地方取的呢?並且還確保我去的存的這個值不會被其他線程所操作的呢 ?通過下面的源碼分析,我們得知是通過當前線程獲取的

set的源碼分析

  • 咦,竟然是通過ThreadLocalMap存的的,那這個ThreadLocalMap 是什麼鬼東西呢,點進去會發現是一個內部類
public void set(T value) { 
	// 獲取當前線程
    Thread t = Thread.currentThread();
    //獲取當前線程所維護的Map
    ThreadLocalMap map = getMap(t);
    if (map != null)
        //將this 傳遞了過去,等於是把當前對象作爲key傳遞過去了
        map.set(this, value);
    else
    //要是Map不存在則創建
        createMap(t, value);
}

// 去獲取值
public ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

// 會發現,如果不存在,則出創建
public void createMap(Thread t, T firstValue) {
	// 那其實創建的時候就是創建一個ThreadLocalMap類,複製給當前線程的threadLocals
   t.threadLocals = new ThreadLocalMap(this, firstValue);
}
  • 分析 ThreadLocalMapset() 方法
private void set(ThreadLocal<?> key, Object value) {
    //具體就是由這個Entry保管了
    tab[i] = new Entry(key, value);
}


  • 分析Entry,會發現這個其實是ThreadLocal的一個內部類
    • key 是ThreadLocal,並且key是存儲在WeakReference弱引用裏面的
    • value是存儲在Entry
static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

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

弱引用、強引用參考

參考:https://www.cnblogs.com/zjj1996/p/9140385.html

  • 可以自己執行一下里面的代碼,會稍微理解一下強弱引用,如果知道堆棧可以理解的更有意思

get的源碼分析

    public T get() {
    	//獲取當前線程
        Thread t = Thread.currentThread();
        //獲取這個Map
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        	//獲取這個包裝類
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
            	//獲取具體的值
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

Thread

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
    //code.....
}

ThreadLocalMap

  • 點進去會發現ThreadLocalMap是ThreadLocal的一個內部類。用Entry類來進行存儲
static class ThreadLocalMap {
//...code
}

具體的流程

  1. 創建了 ThreadLocal
  2. 內部創建ThreadLocalMap
  3. 內部創建了Entry
    1. key 是 ThreadLocal
    2. value 是具體的值
  4. 最後將ThreadLocalMap 賦值給 Thread

在這裏插入圖片描述

閒言

首先讓我們自己設計一個會怎麼樣設計

  • 我們來設計一個這樣的東西會是什麼樣的 ?如果是我,我可能會設計成這樣子的,不要扣這段代碼的邏輯,沒意義
public class MyThreadLocal {
    /**
     * 定義
     */
    private ConcurrentHashMap<Long, Object> threadLocals;

    public void get() {
        Thread thread = Thread.currentThread();
        threadLocals.get(thread.getId());
    }

    public void set(Object value) {
        Thread thread = Thread.currentThread();
        //判斷Map存在不存在,不存在去創建,或者直接創建或者使用內部類懶加載
        threadLocals.put(thread.getId(), value);
    }
}

首先爲什麼ThreadLocalMap 的引用是在Thread

引出問題,先說MyThreadLocal的問題

  1. 首先線程是安全,但是會有鎖的消耗
  2. 其次內存溢出問題,怎麼會內存溢出呢?這就會出現一種情況,雖然線程A,B都已經將棧幀彈出,不繼續使用threadlocal xxx,但是因爲線程C還在使用。甚至之後來線程D,只要仍然有一個線程在使用。即引用(1)仍存,某類就不會被回收,引用(2)仍存。

ThreaLocal

  1. 首先threadLocalsThread持有,由於這樣就不會有鎖消耗和線程安全問題,這樣就控制住了
  2. 其次由於由於ThreadLocal由於一般使用的時候都是設置爲private static
    1. 當static修飾的時候ThreadLocal ref(引用)生命延長
    2. 當static修飾TrheadLocal引用,調用remove(),如果不調用

後言

別鑽死腦筋…

參考

https://blog.csdn.net/weixin_30522183/article/details/96822587

https://blog.csdn.net/silyvin/article/details/79551635

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章