1. 云栖社区>
  2. 博客列表>
  3. 正文

ThreadLocal源码分析

zhang_sl 2016-03-29 21:17:02 浏览1389 评论0

java threadlocal

摘要: Java对象是线程间共享的,但有时我们需要一些线程间隔离的对象,该对象只能由同一个线程读写,对其他线程不可见。ThreadLocal正式提供了这样的机制,本文着重探讨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() {
        return 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
版权声明:本文内容由互联网用户自发贡献,版权归作者所有,本社区不拥有所有权,也不承担相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

用云栖社区APP,舒服~

【云栖快讯】中办国办印发《推进互联网协议第六版(IPv6)规模部署行动计划》加快推进基于 IPv6 的下一代互联网规模部署,计划指出2025年末中国 IPv6 规模要达到世界第一,阿里云也第一时间宣布了将全面提供IPv6服务,那么在全面部署 IPV6 前,你需要了解都在这儿  详情请点击

网友评论

关注
zhang_sl
阿里巴巴天猫无线工程师
11篇文章|4关注

阿里云推出的一款移动App数据统计分析产品,为开发者提供一站式数据化运营服务 更多>

基于全网公开发布数据、传播路径和受众群体画像,利用语义分析、情感算法和机器学习,分析公众对品牌形象、热点事件和公... 更多>

阿里巴巴自主研发的海量数据实时高并发在线分析云计算服务,使得您可以在毫秒级针对千亿级数据进行即时的多维分析透视和... 更多>

为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本... 更多>
订阅广场全新上线

订阅广场全新上线