ThreadLocal爲何是線程安全的

如何看一個類是不是線程安全的?java

     由JMM(Java內存模型)咱們能夠看出,在堆中的變量,若是同時被多個線程操做,就有可能出現線程安全問題(堆中的數據是線程共享的)。數組

     類分爲有狀態(有成員變量等)和無狀態的, 無狀態的類確定是線程安全的, 咱們都知道servlet,還有Spring中的bean都是單例的(在上下文中拿到的對象都是同一個),那它們是怎麼保證線程安全的呢? 首先一點是bean最好是無狀態的,即Dao,Service這些類最好不要有成員變量, 那這種確定是安全的, 若是有怎麼辦, Spring是使用ThreadLocal來保證線程安全的。安全

線程副本this

     每一個線程(Thread)內部都有一個ThreadLocal.ThreadLocalMap, 能夠看出ThreadLocalMap是ThreadLocal的一個靜態內部類, 咱們看一下源碼:線程

       

      從代碼中能夠看出, ThreadLocalMap 裏有一個Entry數組, Entry裏有k, v字段, 而k就是當前的ThreadLocal對應, v就是要保存的變量值。code

      在ThreadLocal中, 使用set, 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();
    }

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

     先從當前線程裏拿到ThreadLocalMap, 而後在從map裏獲取Entry(當前ThreadLocal對應做爲key), entry的value值就是要獲取的變量值;內存

     看出這裏應該就清楚了ThreadLocal是如何保證線程安全的:get

            1. 每一個線程都有一個ThreadLoclMap成員變量(線程副本);源碼

            2. ThreadLocal做爲ThreadLocalMap的'key'來獲取最終變量的值;

     每一個線程拿到的ThreadLocalMap 變量確定是線程私有的,因此不會被其餘線程拿到,這樣也就保證了線程的安全。

相關文章
相關標籤/搜索