ThreadLocal原理分析

ThreadLocal原理分析

ThreadLocal是一个用于实现线程安全的“利器”,主要是通过空间换时间的方法去实现。每一个线程内部都有一个ThreadLocalMap类型的变量,名为threadLocals,这是一个key-value类型的哈希表,键为ThreadLocal实例,要存储的线程局部变量为值

ThreadLocal是怎么用的?

public class BasicExample {
    // 创建一个ThreadLocal变量,并为其提供初始值
    private static ThreadLocal
<Integer> threadLocalCounter = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0; // 返回你想要的初始值
        }
    };

    public static void main(String[] args) {
        Runnable task = () -> {
            // 每个线程都会独立地操作自己的counter副本
            int currentValue = threadLocalCounter.get(); // 获取本线程的值
            threadLocalCounter.set(currentValue + 1); // 修改本线程的值
            System.out.println(Thread.currentThread().getName() + " 的计数器: " + threadLocalCounter.get());

            // !!!重要:使用完毕后及时清理,避免内存泄漏
            threadLocalCounter.remove()[1](@ref);
        };

        new Thread(task, "线程A").start();
        new Thread(task, "线程B").start();
    }
}

ThreadLocal的原理

// ThreadLocal 的 set 方法源码概要
public void set(T value) {
    Thread t = Thread.currentThread(); // 1. 获取当前线程
    ThreadLocalMap map = getMap(t);    // 2. 获取线程的 ThreadLocalMap
    if (map != null) {
        map.set(this, value); // 3. 以当前 ThreadLocal 为键,存储值
    } else {
        createMap(t, value); // 如果 Map 不存在,则创建一个
    }
}

// ThreadLocal 的 get 方法源码概要
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this); // 以当前 ThreadLocal 为键,获取值
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue(); // 如果 Map 不存在或找不到值,则初始化
}

private T setInitialValue() {
    // 1. 获取初始值,默认由 initialValue() 方法提供,通常为 null
    T value = initialValue();
    // 2. 获取当前线程对象
    Thread t = Thread.currentThread();
    // 3. 获取当前线程的 ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 4. 如果 Map 已存在,将当前 ThreadLocal 实例与初始值关联
        map.set(this, value);
    } else {
        // 5. 如果 Map 不存在,则为当前线程创建一个新的 ThreadLocalMap
        createMap(t, value);
    }
    // 6. 返回初始值
    return value;
}

ThreadLocal的内存泄漏是怎么产生的?

根源: ThreadLocalMap中的键(ThreadLocal实例)是弱引用,而值是强引用。如果 ThreadLocal实例被垃圾回收(比如外部将其设为 null),会导致 Map 中的键为 null,但值仍然被强引用且无法再访问到,从而造成内存泄漏

解决方案。每次使用完 ThreadLocal后,在代码块中调用其 remove()方法,显式移除数据。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇