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
目录
相关文章
|
6月前
|
存储 安全 Java
面试题:用过ThreadLocal吗?ThreadLocal是在哪个包下的?看过ThreadLocal源码吗?讲一下ThreadLocal的get和put是怎么实现的?
字节面试题:用过ThreadLocal吗?ThreadLocal是在哪个包下的?看过ThreadLocal源码吗?讲一下ThreadLocal的get和put是怎么实现的?
77 0
|
3月前
|
存储 设计模式 安全
深入理解ThreadLocal原理
本文深入探讨了Java中的ThreadLocal及其内部数据结构ThreadLocalMap的工作原理和特性,帮助读者理解如何利用ThreadLocal实现线程局部变量的隔离和线程安全。
深入理解ThreadLocal原理
|
4月前
|
存储 算法 Java
ThreadLocal 源码浅析
【7月更文挑战第5天】`ThreadLocal` 是Java中用于创建线程局部变量的工具类,确保每个线程拥有独立的变量副本。源码中,每个`ThreadLocal`实例都有一个唯一的哈希码用于映射到`ThreadLocalMap`,这个内部静态类使用弱引用存储键(`ThreadLocal`实例)以防止内存泄漏。`ThreadLocalMap`使用 Entry 数组,Entry 是一个扩展了 WeakReference 的类,持有线程变量值。`ThreadLocal`的`get()`和`set()`方法通过哈希计算定位并访问或设置线程局部变量。
|
6月前
|
存储 安全 Java
ThreadLocal原理讲解
ThreadLocal原理讲解
54 0
|
存储 SpringCloudAlibaba Java
浅析ThreadLocal使用及实现原理
提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其`get` 或 `set`方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。`ThreadLocal`实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联 。所以ThreadLocal与线程同步机制不同,线程同步机制是多个线程共享同一个变量,而ThreadLocal是为每一个线程创建一个单独的变量副本,故而每个线程都可以独立地改变自己所拥有的变量副本,而不会影响其他线程所对应的副本。可以这么说Th
106 0
浅析ThreadLocal使用及实现原理
|
存储 算法 Java
ThreadLocal原理解析
ThreadLocal原理解析
104 1
ThreadLocal原理解析
|
存储 安全 Java
ThreadLocal源码分析
ThreadLocal,即线程局部变量。主要用于线程间数据隔离。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。
|
存储 算法 安全
ThreadLocal原理剖析
ThreadLocal原理剖析
218 0
|
Java 定位技术
ThreadLocal原理
经典八股文之ThreadLocal原理
189 0