ThreadLocal源码分析

ThreadLocal的作用

Java对象是线程间共享的,但有时我们需要一些线程间隔离的对象,该对象只能由同一个线程读写,对其他线程不可见。ThreadLocal正式提供了这样的机制,详细使用方式请参考Java ThreadLocal

ThreadLocal实现原理

自定义实现

在没有看源码前,如果我自己实现一个ThreadLocal,可能是这样的

public class ThreadLocal<T> {
    private Map<Thread, T> values = new WeakHashMap<Thread, T>();

    public synchronized void set(T value) {
        values.put(Thread.currentThread(), value);
    }

    public synchronized T get() {
        values.get(Thread.currentThread());
    }
}

JDK实现

Java源码中ThreadLocal的核心代码如下:

public class ThreadLocal<T> {

    public T get() {
        Thread t = Thread.currentThread();
        //从当前的Thread对象中取出ThreadLocalMap成员,key是ThreadLocal,value是set的值。
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        //从当前的Thread对象中取出ThreadLocalMap成员,key是ThreadLocal,value是set的值。
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

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

}

//threadLocals变量存放在Thread对象中
public class Thread{
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

    ...
}

不同于自定义实现,源码中ThreadLocal.set(T value)的值是由Thread对象来缓存的。那么问题就来了?

1. 为什么ThreadLocal.set(T value)的值由Thread对象来缓存,为什么不像自定义实现那样放在ThreadLocal中?

我理解主要是性能考虑。如果放在ThreadLocal中,由于多线程操作同一个Map对象,将不得不加锁保护。而将value直接放在Thread对象中,不同的线程有各自的Thread对象,因此也就无需加锁。因此将value放在Thread对象中性能会好一些。大家如果有不同的见解,请指教^_^

2. 既然value存放在Thread中,为什么不直接由Thread提供getter/setter接口,而需要额外有一个ThreadLocal类?

我理解此处的value虽然和Thread之间存在映射关系,但是不属于Thread的属性,放在ThreadLocal更多是性能上的考虑,因此由Thread提供getter/setter并不适合。

InheritableThreadLocal原理

InheritableThreadLocal中存放的value是当前线程和当前线程创建出来的子线程可见的。其核心源码如下。

public class Thread {
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        ...

        Thread parent = currentThread();

        ...

        //将parent的inheritableThreadLocals同步到child
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
            //此处create一个新的ThreadLocalMap对象
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

        ...

}

由于child.inheritableThreadLocals是新创建的ThreadLocalMap对象,因此在child中再次执行set,不会影响parent。

参考文献

  1. Java ThreadLocal http://tutorials.jenkov.com/java-concurrency/threadlocal.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值