ThreadLocal基本了解

ThreadLocal

解决的问题:

主要解决的是数据隔离,在多线程的情况下防止自己的变量被修改 。见名知意本地线程,也就是说每个线程都会在ThreadLocal中存放一份属于自己独有的数据,所以它是线程安全的。

相当于Web的域对象,session的作用域是一个会话,而ThreadLocal的作用域就是基本线程。

基本数据结构:

ThreadLocal底层是通过ThreadLocalMap静态内部类实现的,这个ThreadLocalMap就是一个KV的Map集合,底层是一个Entry对象数组,Entry对象存放的K-V分别是ThreadLocal对象和一个Object的值。

在这里插入图片描述

数据进行使用的主要方法:
public void set(T var1) {
    Thread var2 = Thread.currentThread();//首先获取当前线程
 	 //因为Entry对象存的是ThreadLocal和vlaue  
    ThreadLocal.ThreadLocalMap var3 = this.getMap(var2);
    if (var3 != null) {
      //不为空的话进行数据存储
        var3.set(this, var1);
    } else {
      //否则进行创建这个ThreadLocalMap集合
        this.createMap(var2, var1);
    }
}

public T get() {
        Thread var1 = Thread.currentThread();
  			//根据当前线程去获取ThreadLocal.ThreadLocalMap 类型的 threadLocals属性
        ThreadLocal.ThreadLocalMap var2 = this.getMap(var1);
        if (var2 != null) {
          //不为空进行获取对象
            ThreadLocal.ThreadLocalMap.Entry var3 = var2.getEntry(this);
            if (var3 != null) {
                Object var4 = var3.value;
                return var4;
            }
        }
 				//否则进行初始化当前线程
        return this.setInitialValue();
    }
散列方式:

斐波那契散列

处理Hash冲突的方式:

在这里插入图片描述

在set时候如果遇到Hash冲突,使用线性探测法尝试在数组的索引位置进行存储,同时会释放K为null和Value不为null的Entry数组,防止内存泄漏。

如何处理扩容问题:

默认的ThreadLocalMap的大小为16

private static final int INITIAL_CAPACITY = 16;

判断扩容首先会看Entry数组的长度是否大于原始的三分之二,如果大于进行rehash

private void rehash() {
    this.expungeStaleEntries();
  	//最后判断这个条件,满足了 就进行扩容
    if (this.size >= this.threshold - this.threshold / 4) {
        this.resize();
    }
}

在这里插入图片描述

扩容为原来的二倍大小。

如何实现父子线程间局部变量共享问题:

就是实现局部变量直接变量传递:提供了一个InheritableThreadLocal类:可继承线程本地,此类继承的是ThreadLocal类

此时就要翻到Thread类的init方法有这么一段:

如果InheritableThreadLocal不为null,

在这里插入图片描述

跟踪代码一直跳到这段方法里面:

private ThreadLocalMap(ThreadLocal.ThreadLocalMap var1) {
    this.size = 0;
    ThreadLocal.ThreadLocalMap.Entry[] var2 = var1.table;
    int var3 = var2.length;
    this.setThreshold(var3);
    this.table = new ThreadLocal.ThreadLocalMap.Entry[var3];
		//主要在这个循环体里面处理
    for(int var4 = 0; var4 < var3; ++var4) {
        ThreadLocal.ThreadLocalMap.Entry var5 = var2[var4];
        if (var5 != null) {
            ThreadLocal var6 = (ThreadLocal)var5.get();
            if (var6 != null) {
                Object var7 = var6.childValue(var5.value);
                ThreadLocal.ThreadLocalMap.Entry var8 = new ThreadLocal.ThreadLocalMap.Entry(var6, var7);

                int var9;
                for(var9 = var6.threadLocalHashCode & var3 - 1; this.table[var9] != null; var9 = nextIndex(var9, var3)) {
                }

                this.table[var9] = var8;
                ++this.size;
            }
        }
    }

}
为什么会发生内存泄漏:

什么是内存泄漏:是内存中的数据没有被释放或者没法释放,导致系统资源的浪费,造成不可收拾的后果。

发送原因:

因为Entry继承的是WeakReference若引用,而弱引用在系统发生垃圾回收时候会被回收掉,一般会回收那如何会产生内幕才能泄漏;如果是创建ThreadLocal类的线程一直持续运行,那么Entry对象的key就依旧具有强引用而不会被回收而发生内存泄漏。比如线程池里面的线程都是复用的,之前的处理结束,线程而非死亡,处于复用的线程依然存活,

static class Entry extends WeakReference<ThreadLocal<?>> {
    Object value;

    Entry(ThreadLocal<?> var1, Object var2) {
        super(var1);
        this.value = var2;
    }
}
如何解决内存泄漏:

在代码的最后使用remove就好了,我们只要记得在使用的最后用remove把值清空就好了。

ThreadLocal threadLocal = new ThreadLocal();
try{
    threadLocal.set("小明");
}catch (Exception e){
    e.printStackTrace();
}finally {
    threadLocal.remove();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值