ThreadLocal 介绍

是什么

ThreadLocal是Thread的局部变量,用于编多线程程序,对解决多线程程序的并发问题有一定的启示作用。每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离。

ThreadLocal源码

public class ThreadLocal<T> {
    private final int threadLocalHashCode = nextHashCode();
    //AtomicInteger保证了nextHashCode自增的原子性
    private static AtomicInteger nextHashCode = new AtomicInteger();
    private static final int HASH_INCREMENT = 1640531527;

    private static int nextHashCode() {
        return nextHashCode.getAndAdd(1640531527);
    }

    protected T initialValue() {
        return null;
    }

    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
        return new ThreadLocal.SuppliedThreadLocal(supplier);
  

方法

  • get() 用来获取ThreadLocal在当前线程中保存的变量副本。
  • set() 设置当前线程中变量的副本。
  • remove() 移除当前线程中变量的副本。
  • initialValue()是一个protected方法,一般是用来在使用时进行重写的
ThreadlocalMap
  • 是用来存储当前线程的变量,是内部类
  • 初始容量16,负载因子2/3
static class ThreadLocalMap {
        private static final int INITIAL_CAPACITY = 16;
        //存放数据的table
        private ThreadLocal.ThreadLocalMap.Entry[] table;
        //数组里面entrys的数量
        private int size = 0;
        // 进行扩容的阈值,表使用量大于它的时候进行扩容
        private int threshold; //默认是0
存储结构——Entry

/**
 * Entry继承WeakReference,并且用ThreadLocal作为key.如果key为null
 * (entry.get() == null)表示key不再被引用,表示ThreadLocal对象被回收
 * 因此这时候entry也可以从table从清除。
 */
 //弱引用避免因为线程得不到销毁导致ThreadLocal对象无法被回收
 static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                this.value = v;
            }
        }
set
//set 方法
public void set(T value) {
      //获取当前线程
      Thread t = Thread.currentThread();
      //实际存储的数据结构类型
      ThreadLocalMap map = getMap(t);
      //如果存在map就直接set,没有则创建map并set
      if (map != null)
          map.set(this, value);
      else
          createMap(t, value);
  }
  
//getMap
ThreadLocalMap getMap(Thread t) {
      //thred中维护一个ThreadLocalMap
      return t.threadLocals;
 }
 
//createMap
void createMap(Thread t, T firstValue) {
      //实例化一个新的ThreadLocalMap,并赋值给线程的成员变量threadLocals
      t.threadLocals = new ThreadLocalMap(this, firstValue);
}

获取当前线程,并获取当前线程的ThreadLocalMap实例
如果获取到的map实例不为空,调用map.set()方法,否则调用构造函数 ThreadLocal.ThreadLocalMap(this, firstValue)实例化map。

get
 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocal.ThreadLocalMap map = this.getMap(t);
        if (map != null) {
            ThreadLocal.ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                T result = e.value;
                return result;
            }
        }

        return this.setInitialValue();
    }
setInitialValue()
private T setInitialValue() {
        T value = this.initialValue();
        Thread t = Thread.currentThread();
        ThreadLocal.ThreadLocalMap map = this.getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            this.createMap(t, value);
        }

        if (this instanceof TerminatingThreadLocal) {
            TerminatingThreadLocal.register((TerminatingThreadLocal)this);
        }

        return value;
    }

map不为空,就设置键值对,为空,再创建Map

特点

  • ThreadLocalMap的数据结构仅仅是数组
  • ThreadLocalMap 是通过开放地址法来解决hash 冲突的问题
  • ThreadLocalMap里面的Entry 内部类中的key 是弱引用,value 是强引用

应用场景

  • Session管理
    • 数据库session
  • Cookie和Session

内存泄漏

ThreadLocalMap使用ThreadLocal的弱引用作为Entry的key,如果一个ThreadLocal没有外部强引用来引用它,下一次系统GC时,这个ThreadLocal必然会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value
解决方法

为什么用ThreadLocal作为key

每一个ThreadLocal对象都可以由threadLocalHashCode属性唯一区分或者说每一个ThreadLocal对象都可以由这个对象的名字唯一区分。

为什么要用弱引用

使用弱引用,可以将ThreadLocal对象的生命周期和线程生命周期解绑,持有对ThreadLocal的弱引用,可以使得ThreadLocal在没有其他强引用的时候被回收掉,这样可以避免因为线程得不到销毁导致ThreadLocal对象无法被回收。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值