ThreadLocal知识总结

1、ThreadLocal介绍:

多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
threadlocal访问过程
在这里插入图片描述

  • ThreadLocal使用demo:
public class ThreadLoaclDemo {

    private static ThreadLocal<String> counterHolder =
            new ThreadLocal<>();

    static void print(String str){
        System.out.println(str+" : "+counterHolder.get());
        //清楚本地内存中的本地内存
        counterHolder.remove();
    }


    public static void main(String[] args) {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                counterHolder.set("fun-1");
                print("thread-1");
                System.out.println("after remove : "+counterHolder.get());
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                counterHolder.set("fun-2");
                print("thread-2");
                System.out.println("after remove : "+counterHolder.get());
            }
        });

        t1.start();
        t2.start();
    }
}

  • ThreadLocal的set方法源码
1 public void set(T value) {
 2     //(1)获取当前线程(调用者线程)
 3     Thread t = Thread.currentThread();
 4     //(2)以当前线程作为key值,去查找对应的线程变量,找到对应的map
 5     ThreadLocalMap map = getMap(t);
 6     //(3)如果map不为null,就直接添加本地变量,key为当前定义的ThreadLocal变量的this引用,值为添加的本地变量值
 7     if (map != null)
 8         map.set(this, value);
 9     //(4)如果map为null,说明首次添加,需要首先创建出对应的map
10     else
11         createMap(t, value);
12 }
  • ThreadLocalt的get方法源码
	     public T get() {
	2     //(1)获取当前线程
	3     Thread t = Thread.currentThread();
	4     //(2)获取当前线程的threadLocals变量
	5     ThreadLocalMap map = getMap(t);
	6     //(3)如果threadLocals变量不为null,就可以在map中查找到本地变量的值
	7     if (map != null) {
	8         ThreadLocalMap.Entry e = map.getEntry(this);
	9         if (e != null) {
	10             @SuppressWarnings("unchecked")
	11             T result = (T)e.value;
	12             return result;
	13         }
	14     }
	15     //(4)执行到此处,threadLocals为null,调用该更改初始化当前线程的threadLocals变量
	16     return setInitialValue();
	17 }
	18 
	19    private T setInitialValue() {
	20     //protected T initialValue() {return null;}
	21     T value = initialValue();
	22     //获取当前线程
	23     Thread t = Thread.currentThread();
	24     //以当前线程作为key值,去查找对应的线程变量,找到对应的map
	25     ThreadLocalMap map = getMap(t);
	26     //如果map不为null,就直接添加本地变量,key为当前线程,值为添加的本地变量值
	27     if (map != null)
	28         map.set(this, value);
	29     //如果map为null,说明首次添加,需要首先创建出对应的map
	30     else
	31         createMap(t, value);
	32     return value;
	33 }
  • ThreadLocal的remove方法的源码
 public void remove() {
2     //获取当前线程绑定的threadLocals
3      ThreadLocalMap m = getMap(Thread.currentThread());
4      //如果map不为null,就移除当前线程中指定ThreadLocal实例的本地变量
5      if (m != null)
6          m.remove(this);
7  }

2、ThreadLocal不支持继承性

同一个ThreadLocal变量在父线程中被设置值后,在子线程中是获取不到的。(threadLocals中为当前调用线程对应的本地变量,所以二者自然是不能共享的)。但是InheritableThreadLocal可以做到这个功能。

3、ThreadLocl内存泄漏问题

THreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用,在没有其他地方对ThreadLoca依赖,ThreadLocalMap中的ThreadLocal对象就会被回收掉,但是对应的不会被回收,这个时候Map中就可能存在key为null但是value不为null的项,这需要实际的时候使用完毕及时调用remove方法避免内存泄漏。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值