Java并发(三) ThreadLocal关键字

来源:互联网 发布:西蒙智力量表软件 编辑:程序博客网 时间:2024/04/30 10:57

TheadLocal称为线程本地存储,就是说一个变量,每个线程都有它的一个副本,并且相互之间是独立的。

ThreadLocal类的实现

下面是该类的提供的关键的几个方法:

public T get() { }public void set(T value) { }public void remove() { }protected T initialValue() { }

通过查看jdk中该类的源码,可以大致看到上述方法的实现,其中:

    /**     * Returns the value in the current thread's copy of this     * thread-local variable.  If the variable has no value for the     * current thread, it is first initialized to the value returned     * by an invocation of the {@link #initialValue} method.     *     * @return the current thread's value of this thread-local     */    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();    }

是get()方法的实现,首先是通过一个getMap得到ThreadLocalMap,然后在这个ThreadLocalMap中通过this来获得对应的值作为返回值:如果将ThreadLocalMap看作map的话,我们可以发现实际上这个map的key是当前的ThreadLoca变量。
接下来看getMap方法的实现

    /**     * Get the map associated with a ThreadLocal. Overridden in     * InheritableThreadLocal.     *     * @param  t the current thread     * @return the map     */    ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }

实际上就是返回了线程t的成员变量threadLocals,该变量是一个ThreadLocalMap类型。

这样我们就可以总结出TheadLocal大致的工作原理:有依附于每个线程的一个ThreadLocalMap的类似map的数据结构,这个数据结构的key就是我们定义的ThreadLocal变量,同时我们可以定义多个ThreadLocal变量作为这个map的key。
用图形表示为:
这里写图片描述
从这里来看,ThreadLocal其实只是相当于声明了某种类型是线程本地存储,实际上的数据是存储在每个Thread实例的成员变量中的。这也就是线程本地存储名称的来源—数据实际上存储在本地线程中。
另外还有set:

    /**     * Sets the current thread's copy of this thread-local variable     * to the specified value.  Most subclasses will have no need to     * override this method, relying solely on the {@link #initialValue}     * method to set the values of thread-locals.     *     * @param value the value to be stored in the current thread's copy of     *        this thread-local.     */    public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }

用于修改value值。

另外注意到,ThreadLocalMap中的内部类Entry是声明为WeakReference,这是java中的四种Reference类型之一。通过相关相关书籍和网页,简单介绍一下:
StrongReference,就是我们通常通过new Object()这样的形式得到的引用,叫强引用,只要强引用还在,GC就不会回收相应的对象。
SoftReference,软引用,系统在内存将要溢出之前,会对这类引用的对象进行清理。比如外部数据源:文件、数据库、网络等可声明为该类型引用。
WeakReference,弱引用,被弱引用关联的对象如果被JVM识别为弱可达,那么在下次GC的时候就会进行回收。
SoftReference与WeakReference的区别是GC的时间是尽量推迟的。
Phantom,虚引用。不能通过虚引用来获得一个对象实例,唯一的目的是在对象被回收时得到一个系统通知。

ThreadLocal应用场景

数据库连接、Session管理等

0 0