美文网首页
Java并发编程:ThreadLocal的理解

Java并发编程:ThreadLocal的理解

作者: 对面的你 | 来源:发表于2018-09-21 17:59 被阅读10次

前言

java内存模型

java虚拟机,模仿真实的计算机结构,为java中各个变量、实例分配内存空间。主要有:

  1. 方法区:类信息、常量、静态变量、即时编译器编译后的代码数据。方法区包括运行时常量池:字面量、符号引用
  2. 堆:线程共享的内存区域,存放对象实例
  3. 程序计数器:
  4. 虚拟机栈:线程私有数据区域,每个方法执行时都会创建一个栈帧,存储方法的变量表、操作数栈、动态链接、返回值、返回地址等信息。
  5. 本地方法栈:线程私有数据区域,与native代码相关。

ThreadLocal在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。
虽然ThreadLocal能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用ThreadLocal要大。

ThreadLocal类

ThreadLocal是如何为每个变量建立副本的。

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();
}

获取当前线程的ThreadLocalMap,获取成功则返回value值,失败则调用setInitialValue()。

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

threadLoacls是一个ThreadLoaclMap类型,他是ThreadLoacl类的内部类:

static class ThreadLocalMap {

    /**
     * The entries in this hash map extend WeakReference, using
     * its main ref field as the key (which is always a
     * ThreadLocal object).  Note that null keys (i.e. entry.get()
     * == null) mean that the key is no longer referenced, so the
     * entry can be expunged from table.  Such entries are referred to
     * as "stale entries" in the code that follows.
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

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

Entry类是ThreadLocalMap的内部类,且继承自WeakReference,并且使用ThreadLoacl类型作为键值。

private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
  1. 在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)
  2. 在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。
  3. 然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。

通俗说明就是,每个线程在创建的时候都会创建自己ThreadLocal类型的私有对象,通过这个私有对象作为Thread里的map的key值,可以找出对应的value,从而达到线程间value复制且不相互影响的作用。

相关文章

网友评论

      本文标题:Java并发编程:ThreadLocal的理解

      本文链接:https://www.haomeiwen.com/subject/qatonftx.html