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 变量确定是线程私有的,因此不会被其余线程拿到,这样也就保证了线程的安全。

相关文章
相关标签/搜索