ThreadLocal

本贴最后更新于 1610 天前,其中的信息可能已经水流花落

wolfganghasselmannuNr07wgn5y4unsplash.jpg

功能

  • 让每个线程使用一个独立的副本数据

源码

  • class ThreadLocalMap {
        class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
    
            Entry(ThreadLocal<?> k, Object v) {
                super(k);// 关键是这行代码,调用父类的构造方法,才将k这个对象设置为弱引用对象
                value = v;
            }
    
            private void set(ThreadLocal<?> key, Object value) {
                Entry[] tab = table;
                int len = tab.length;
                int i = key.threadLocalHashCode & (len-1);
    
                for (Entry e = tab[i];
                     e != null;
                     e = tab[i = nextIndex(i, len)]) {
                    ThreadLocal<?> k = e.get();
    
                    if (k == key) {
                        e.value = value;
                        return;
                    }
    
                    if (k == null) {
                        replaceStaleEntry(key, value, i);
                        return;
                    }
                }
                ......
            }
    
            private static int nextIndex(int i, int len) {
                return ((i + 1 < len) ? i + 1 : 0);
            }
        }
    }
    
  • private int expungeStaleEntry(int staleSlot) {
        Entry[] tab = table;
        int len = tab.length;
    
        tab[staleSlot].value = null;
        tab[staleSlot] = null;
        size--;
        ......
    }
    

使用流程

先看下面这段代码

public class ThreadLocalRunner {
    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                threadLocal.set(0);
                for (int j = 1; j <= 100; j++) {
                    threadLocal.set(threadLocal.get() + j);
                }
                System.out.println("线程" + Thread.currentThread() + "的执行结果为:" + threadLocal.get());
            }).start();
        }
    }
}

这段代码的运行结果会是下面这样的
UHwqkq.png

10 个线程都是用的同一个 threadLocal 对象,但是在使用 threadLocal.set(xx) 时会创建各自的 ThreadLocalMap 对象并且绑定在自己的线程对象里,代码如下

    // java.lang.ThreadLocal.java
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
  
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

当调用 threadLocal.get() 方法时也是使用自己线程的 ThreadLocalMap 对象获取值,代码:

    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;
    }
  • 代码
    467 引用 • 586 回帖 • 9 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖 • 1 关注

相关帖子

3 回帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...