2024-03-23  阅读(111)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/9031040644

回答

ThreadLocal 是 Java 并发中一个非常重要的类,是用来解决Java多线程程序中并发问题的一种途径。它为每个使用该变量的线程提供一个独立的变量副本,因此每个线程都可以独立地改变自己的副本,而不会影响其他线程中的副本,线程之间的竞态条件被彻底消除了。

ThreadLocal 的核心原理是为每个线程提供一个独立的变量副本,从而实现线程之间的数据隔离。这是通过在每个线程内部维护一个名为 ThreadLocalMap 的映射来实现的,其中键是 ThreadLocal 对象,值是线程特有的变量副本。这样,每个线程只能访问和修改自己的变量副本,而不会干扰到其他线程。为了避免内存泄漏,ThreadLocalMap 使用弱引用作为键,所以我们在使用的时候需要手动清理 ThreadLocal 变量。

ThreadLocal 实现原理详解

Thread、ThreadLocal、ThreadLocalMap 三者之间的关系

要掌握 ThreadLocal 的核心原理,第一要务就是要厘清楚 Thread、ThreadLocal、ThreadLocalMap 三者之间的关系。

Thread 里面有一个 ThreadLocalMap 的成员变量 threadLocals:

ThreadLocal.ThreadLocalMap threadLocals = null;

从这里可以看出,每个线程都有自己的 ThreadLocalMap。ThreadLocalMap 是 ThreadLocal 的静态内部类:

public class ThreadLocal<T> {
 
    static class ThreadLocalMap {

   
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
 
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
 
        private Entry[] table;
     
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }
 
    }

ThreadLocalMap 内部维护的是一个或者多个Entry<k,v>,每个 Entry 的 key 是ThreadLocal 实例的弱引用,value 则线程的专属变量。关系如下:

我们看下 ThreadLocalget() 源码:

    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 getMap(Thread t) {
        return t.threadLocals;
    }

操作顺序是这样的:ThreadLocalMap map = thread.threadLocals —> return map.getEntry(threadLocal)。这里我们可以再次进一步理解他们的关系:

set() 的源码:

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

操作顺序是这样的:ThreadLocalMap map = thread.threadLocals —> map.set(threadLocal, value),再次精进他们的关系:

源码及使用方法大明哥就不阐述了,ThreadLocal 的源码很简单,重点在于理解 Thread、ThreadLocal、ThreadLocalMap 之间的关系。

https://www.skjava.com/series/article/8307693980

阅读全文
  • 点赞