【java之juc并发包系列教程】一文看懂ThreadLocal底层实现

8 篇文章 4 订阅
2 篇文章 0 订阅


前言

一、ThreadLocal是什么?

此类提供线程局部变量。这些变量不同于它们的正常对应变量,因为每个访问一个(通过它的 get 或 set 方法)的线程都有它自己的、独立初始化的变量副本。 ThreadLocal 实例通常是希望将状态与线程相关联的类中的私有静态字段(例如,用户 ID 或事务 ID)。例如,下面的类生成每个线程本地的唯一标识符。线程的 id 在第一次调用 ThreadId.get() 时被分配,并且在后续调用中保持不变。

import java.util.concurrent.atomic.AtomicInteger;
  
   public class ThreadId {
       // Atomic integer containing the next thread ID to be assigned
       private static final AtomicInteger nextId = new AtomicInteger(0);
  
       // Thread local variable containing each thread's ID
       private static final ThreadLocal<Integer> threadId =
           new ThreadLocal<Integer>() {
               @Override protected Integer initialValue() {
                   return nextId.getAndIncrement();
           }
       };
  
       // Returns the current thread's unique ID, assigning it if necessary
       public static int get() {
           return threadId.get();
       }
   }

只要线程处于活动状态并且 ThreadLocal 实例是可访问的,每个线程都持有对其线程局部变量副本的隐式引用;在线程消失后,它的所有线程本地实例副本都将受到垃圾回收(除非存在对这些副本的其他引用)。自:1.2 作者:Josh Bloch 和 Doug Lea

二、ThreadLocal对象

简单使用其实就是new出对象,然后get和set方法

先看看new ThreadLocal()

在这里插入图片描述
初始化就new了对象其他什么都没干

threadLocal.set(T value)方法

	//将此线程局部变量的当前线程副本设置为指定值。大多数子类不需要重写此方法,仅依靠 initialValue 方法来设置线程局部变量的值。
	//参数:
//value – 要存储在此线程本地的当前线程副本中的值。
    public void set(T value) {
        Thread t = Thread.currentThread();//获取当前线程对象
        ThreadLocalMap map = getMap(t);  //调用本地getMap方法返回ThreadLocalMap
        if (map != null) {//如果ThreadLocalMap不为空就设置值,key为threadLocal对象本身
            map.set(this, value);
        } else {//如果ThreadLocalMap为空,就创建ThreadLocalMap并赋值
            createMap(t, value);
        }
    }

关于ThreadLocalMap介绍可以看这篇文章,这里先不多介绍,用法类似于Maphttps://blog.csdn.net/zt011052/article/details/90055586
我们进入getMap方法看看
在这里插入图片描述
返回了线程对象threadLocals属性,看Thread源码
在这里插入图片描述
说明Thread对象本身持有了ThreadLocalMap类型的对象,只有ThreadLocal初次赋值时候才会实例化
所以我们在查看threadLocal.createMap(t, value);方法
在这里插入图片描述
原来这里就是创建ThreadLocalMap对象并赋值给Thread的threadLocals属性

threadLocal.get()方法

public T get() {
        Thread t = Thread.currentThread(); //获取当前线程
        ThreadLocalMap map = getMap(t);//获取当前线程持有的ThreadLocalMap对象
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); //通过key也就是threadLocal来获取值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //没有获取到就设置初始化值并返回
        return setInitialValue();
    }

setInitialValue()方法

private T setInitialValue() {
        T value = initialValue();//获取初始化值,在这里其实就是返回null
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
        if (this instanceof TerminatingThreadLocal) {
            TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
        }
        return value;
    }

到这里其实原理已经明了了,并且也不难看出ThreadLocal只能是一个线程中设置和获取值,对于子线程是获取不到父线程的值的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值