初探ThreadLocal

在使用spring boot的時候,發現這麼樣一個很有意思的功能:

RequestContextHolder.getRequestAttributes()).getRequest()

可以通過這麼樣的一個類來獲取當前的Request對象,第一反應就是spring boot替我們完成了request對象與當前線程的綁定。

那這內部,又是如何實現的?

這個RequestContenxtHolder裏面有一個ThreadLocal對象,這個對象,就是實現數據與線程綁定的核心對象。

那麼ThreadLocal又是什麼?

從源碼的註釋大概可以瞭解到,這個類可以用來實現線程本地變量,我們來做個試驗:

public class Main{
    
    private ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public void set(String str){
        threadLocal.set(str);
    }

    public String get(){
        return threadLocal.get();
    }

    public static void main(String[] args) throws InterruptedException {

        Main main = new Main();
        main.set("hello");
        Thread thread = new Thread(()->main.set("world"));

        thread.start();
        thread.join();
        System.out.println(main.get());

    }
}

當運行這個程序的時候,會輸出什麼?

結果是hello,由於thread線程肯定是會在set("hello")之後,join()之前運行完畢的,所以我們可以從這個小例子當中初步瞭解ThreadLocal的用法。

那麼我們知道,在JAVA內存模型當中,分爲公共內存和線程私有內存,或者也叫工作內存。

線程私有內存是在棧上,那麼我們能不能據此判斷,ThreadLocal對象是在棧上?

繼續看源碼:

set方法:

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方法:

public T get() {
        Thread t = Thread.currentThread();
        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();
    }

getMap方法:

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

 

從這三個方法來看,線程對象內部有一個ThreadLocal.ThreadLocalMap對象:

正是通過這個map,才實現了ThreadLocal與數據的綁定

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