ThreadLocal核心源码阅读

1. 概述

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

入门例子:

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局部属性字段

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}

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

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 常用方法源码阅读:

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清除一下。
在这里插入图片描述

测试代码如下:

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
在这里插入图片描述
运行截图:

在这里插入图片描述

相关推荐

  1. ThreadLocal(4):ThreadLocal核心方法

    2024-04-07 12:12:03       29 阅读
  2. FutureTask阅读

    2024-04-07 12:12:03       39 阅读
  3. 阅读】evmⅡ

    2024-04-07 12:12:03       17 阅读
  4. kubelet阅读

    2024-04-07 12:12:03       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-07 12:12:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-07 12:12:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-07 12:12:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-07 12:12:03       20 阅读

热门阅读

  1. 4.6

    2024-04-07 12:12:03       14 阅读
  2. JVM常量池

    2024-04-07 12:12:03       18 阅读
  3. MySQL中的事务隔离级别与MVCC及两者间的关联

    2024-04-07 12:12:03       15 阅读
  4. Netty和websocket,如何部署Netty

    2024-04-07 12:12:03       13 阅读
  5. 用FPGA搞图像算法需要具备哪些基础

    2024-04-07 12:12:03       12 阅读
  6. 手写一个民用Tomcat (02)

    2024-04-07 12:12:03       15 阅读
  7. 计算机网络的分层结构及模型

    2024-04-07 12:12:03       16 阅读