ThreadLocal

1、Threadlocal 背景、原理

背景:对于一个变量,如果多个线程需要操作该变量该怎么做,而且该变量在各个线程内还要代表不同的值(线程间不需要据此变量通信)

      对于上述问题,首先可以加锁解决,但是总感觉不够灵活,浪费资源;其实这就可以用 ThreadLocal

原理:先写个例子再理解原理比较好(如下)

   这里就简单举例(每个线程在自己执行体内都调用 threadlocal设置了值或去获取值)

    public static void main(String[] args) throws InterruptedException {

        ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

        //主线程设置下 最后取出
        threadLocal.set(100);
        Thread thead1 = new Thread(new Runnable() {
            @Override
            public void run() {
          //它会为null 因为你没在该执行体设置值 System.out.println(Thread.currentThread().getName()
+"```:"+threadLocal.get());// null } }, "thead1"); thead1.start(); Thread thead2 = new Thread(new Runnable() { @Override public void run() { threadLocal.set(10) ; System.out.println(Thread.currentThread().getName()+"```:"+threadLocal.get());// null } }, "thead2"); thead2.start(); //这个只是为了等待线程1 2 执行完,让代码按顺序执行 thead1.join(); thead2.join(); //main线程 System.out.println(threadLocal.get());//100
}

原理:表面看上去是在 ThreadLocal 内存了值,其实并不是;threaLocal 只是一个key

           我们需要知道,每个线程都有自己的map (ThreadLocal.ThreadLocalMap threadLocals )

   这个 map 是以Entry为存储单元的数组,看源码很清晰的;

          所以,每个线程都会根据key计算想要存储的这个元素的位置(hash),确定之后,以 Entry 得形式存入,这个Entry也是key value;没错这个key就是threadLocal 和上述计算位置的key一样

          取得时候就根据线程自己的threadlocal去取即可,这就是原理

另外ThreadLocal得另一个经典问题就是:内存泄漏;

原因: 当一个生成生命周期很长得时候,加入你此时使用了threadLocal ,然后使用结束了,但是线程没结束,所以ThreadLocalMap依然存在,所以里面的key value 依然存在;这就造成了内存泄漏

对策: Entry 里的key是一个虚引用,但它也仅仅是解决了key得回收问题,

    不过呢,value当然也可据此回收,判断key为null,那就对它进行回收,那不就妥了 哈哈

        所以,threadlocal 每次set get remove 都会去判断key对key进行回收,所以我们想避免那就记得不用了记得remove即可

疑问:为啥不把value也置为虚引用?

 答:key 还没回收,value就没了,那你说咋办?

疑问:key 为虚引用?能不能模拟一下咋就为虚引用了?

           你在线程内把threadlocal置为null,且其他地方别用;他就是虚引用了           

原文地址:https://www.cnblogs.com/blog-tian/p/15545018.html