ThreadLocal 源码解析

1 简介

ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

2 demo

ThreadLocal 作用: 人手一份。

public class ThreadLocalTest {


    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);


    private static void setValue(Integer value) {

        threadLocal.set(value);

    }

    public static void main(String[] args) throws InterruptedException {


        Thread t1 = new Thread(() -> {
            try {
                setValue(1);
                System.out.println(Thread.currentThread().getName() + " thread local is: " + threadLocal.get());
            } finally {
                threadLocal.remove();
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            try {
                setValue(2);
                System.out.println(Thread.currentThread().getName() + " thread local is: " + threadLocal.get());
            } finally {
                threadLocal.remove();
            }
        }, "t2");

        Thread t3 = new Thread(() -> {
            try {
                setValue(3);
                System.out.println(Thread.currentThread().getName() + " thread local is: " + threadLocal.get());
            } finally {
                threadLocal.remove();
            }
        }, "t3");


        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

    }

}

在这里插入图片描述

3 ThreadLocal 源码解析

3.1 ThreadLocalMap

(1) ThreadLocalMap
ThreadLocalMap 是ThreadLocal的内部静态类。key是虚引用的ThreadLocal,value是一个Object。
在这里插入图片描述
(2) ThreadLocalMap 和 Thread之间的关系

每一个Thread都有一个ThreadLocalMap。
在这里插入图片描述

3.2 set

   public void set(T value) {
        //1 获取当前线程
        Thread t = Thread.currentThread();
        //2 获取线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //3 如果map不为空给map设置值,key是当前创建的threadLocal,如果map为空创建map
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

在这里插入图片描述

 void createMap(Thread t, T firstValue) {
 		// ThreadLocal.ThreadLocalMap threadLocals 赋值
 		// 每个线程都有自己的ThreadLocalMap(人手一份)。
        t.threadLocals = new ThreadLocalMap(this, firstValue);
 }

在这里插入图片描述

3.3 get

public T get() {
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果map不为空
        if (map != null) {
             //获取value
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //初始化ThreadLocalMap
        return setInitialValue();
    }

在这里插入图片描述

3.4 remove

 public void remove() {
 		//获取当前线程的ThreadLocalMap
         ThreadLocalMap m = getMap(Thread.currentThread());
         //如果m!=null  移除
         if (m != null)
             m.remove(this);
     }

在这里插入图片描述

3.5 ThreadLocalMap 为什么使用弱引用?

防止ThreadLocal对象无法被回收。
每个Thread中都存在一个ThreadLocalMap,并且ThreadLocalMap中的key是以threadlocal实例。每个key都弱引用指向threadlocal。所以当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal就可以顺利被gc回收。
假如每个key都强引用指向threadlocal,那么这个threadlocal就会因为和entry存在强引用无法被回收,造成内存泄漏。除非线程结束,线程被回收了,map也跟着回收。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

响彻天堂丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值