ThreadLocal核心源码阅读

1. 概述

ThreadLocal为每个使用该变量的线程提供独立的变量副本,因此每一个线程都可以独立地改变自己的副本,而不会影响其他线程。

入门例子:

java 复制代码
public class ThreadLocalStudy {

    static ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        new Thread(
                () -> {
                    stringThreadLocal.set("5");
                    System.out.println(stringThreadLocal.get());
                    test();
                }
        ).start();
        TimeUnit.SECONDS.sleep(10);
    }

    public static void test() {
        System.out.println(stringThreadLocal.get());
    }
}

2. 源码阅读

ThreadLocal.ThreadLocalMap threadLocals 是 Thread局部属性字段

java 复制代码
public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}

ThreadLocal.ThreadLocalMap

key: ThreadLocal 弱引用 value: 对应的值

java 复制代码
static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }

private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
private int size = 0;
private int threshold; // Default to 0
private void setThreshold(int len) {
    threshold = len * 2 / 3;
}
private static int nextIndex(int i, int len) {
    return ((i + 1 < len) ? i + 1 : 0);
}
private static int prevIndex(int i, int len) {
    return ((i - 1 >= 0) ? i - 1 : len - 1);
}

ThreadLocal 常用方法源码阅读:

java 复制代码
public void set(T value) {
    Thread t = Thread.currentThread();
    // 1. 获取当前线程的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null)
        // 2.1 设置值 key:stringThreadLocal value: 对应的值
        map.set(this, value);
    else
        // 2.2 创建Map
        createMap(t, value);
}

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

void createMap(Thread t, T firstValue) {
    // ThreadLocalMap key: stringThreadLocal value: 对应的值
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

public T get() {
    Thread t = Thread.currentThread();
    // 1. 获取当前线程的threadLocals
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 2. 使用key stringThreadLocal 获取 Entry
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            // 返回结果
            return result;
        }
    }
    // threadLocals 设置value为null的键值对,并返回null
    return setInitialValue();
}

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

// 移除当前线程的 threadLocals中 stringThreadLocal 的键值对
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
     if (m != null)
         m.remove(this);
     }
}

3. ThreadLocalMap的key为什么用弱引用

当 线程中的 threadLocal 被GC回收,threadLocal在堆中只有弱引用指向,就可以被回收了,但是value不会被回收,所以还是会有内存泄漏的情况,所以代码运行完成要用 remove清除一下。

测试代码如下:

java 复制代码
public class ThreadLocalStudy {

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i <= 100; i++) {
            System.out.println(i);
            TimeUnit.SECONDS.sleep(1);
            new Thread(
                    () -> {
                        ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();
                        byte[] oneM = new byte[1024 * 1024];
                        threadLocal.set(oneM);
                        System.out.println(threadLocal.get().length);
                        // 切断threadLocal的强引用
                        threadLocal = null;

                        System.gc();

                        try {
                            TimeUnit.SECONDS.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            ).start();

        }
        TimeUnit.MINUTES.sleep(100);
    }
}

堆大小 20m

运行截图:

相关推荐
Source.Liu13 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng13 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马16 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng20 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香21 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员22 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU22 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie626 分钟前
在IDEA中使用Git
java·git
小白学大数据29 分钟前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
VBA633730 分钟前
VBA之Word应用第三章第三节:打开文档,并将文档分配给变量
开发语言