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

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

文章目录

  • 前言
  • 一、ThreadLocal是什么?
  • 二、ThreadLocal对象
    • 先看看new ThreadLocal()
    • threadLocal.set(T value)方法
    • threadLocal.get()方法
  • 到这里其实原理已经明了了,并且也不难看出ThreadLocal只能是一个线程中设置和获取值,对于子线程是获取不到父线程的值的

前言

一、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 assignedprivate static final AtomicInteger nextId = new AtomicInteger(0);  // Thread local variable containing each thread's IDprivate 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 necessarypublic static int get() {    return threadId.get();}   }

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

二、ThreadLocal对象

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

先看看new ThreadLocal()

【java之juc并发包系列教程】一文看懂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方法看看
【java之juc并发包系列教程】一文看懂ThreadLocal底层实现
返回了线程对象threadLocals属性,看Thread源码
【java之juc并发包系列教程】一文看懂ThreadLocal底层实现
说明Thread对象本身持有了ThreadLocalMap类型的对象,只有ThreadLocal初次赋值时候才会实例化
所以我们在查看threadLocal.createMap(t, value);方法
【java之juc并发包系列教程】一文看懂ThreadLocal底层实现
原来这里就是创建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只能是一个线程中设置和获取值,对于子线程是获取不到父线程的值的