ThreadLocal 原理及例子

导读:本篇文章讲解 ThreadLocal 原理及例子,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

通俗解释

三大特点:

经典案例:

和synchronized的区别

应用场景

ThreadLocal 数据结构图示

ThreadLocal 的内存泄漏

那么为什么key要用弱引用呢?

弱引用


黑马程序员Java基础教程由浅入深全面解析threadlocal_哔哩哔哩_bilibili刚接触的学员可以直接看零基础java入门av80585971课程全面,包含:ThreadLocal基本介绍,运用场景,源码分析,常见面试问题等结合源码和画图解构ThreadLocal,更加形象源码分析不仅仅停留在表面,有源码为何这样设计的思考覆盖常见的面试问题: 如TheadLocal和synchronized关键字和内存泄漏方面都有深入的分析ThreadLocal 原理及例子https://www.bilibili.com/video/BV1N741127FH?p=10&spm_id_from=pageDriver 由浅入深,全面解析ThreadLocal_LeslieGuGu的博客-CSDN博客_threadlocalThreadLocal 原理及例子https://blog.csdn.net/weixin_44050144/article/details/113061884

通俗解释

ThreadLocal 就是每一个线程自己维护的一个map中的key,

比如t1线程有自己的ThreadLocalMap1,里面存放着 ThreadLocal 1, value1

t2线程有自己的ThreadLocalMap2,里面存放着 ThreadLocal 2, value2.

在使用的时候 通过当前线程直接得到自己内部的map,再用键直接取出值即可。

三大特点:

  1. 线程并发: 在多线程并发的场景下
  2. 传递数据: 我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量
  3. 线程隔离: 每个线程的变量都是独立的,不会互相影响,各是各的

经典案例:

下面这个例子中 如果不用threadlocal ,那么会出现 线程1设置了content,线程3把content取出来了,因为并发场景且没有加锁,content只有1份。 使用threadlocal ,设置值的时候,这个content相当于和这个线程关联上了,所以在取值的时候也和这个线程是对应的,所以其实这个content有5份,每个线程都有一份

public class MyDemo1 {

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

    private String content;

    private String getContent() {
        return tl.get();
    }

    private void setContent(String content) {
         tl.set(content);
    }

    public static void main(String[] args) {
        MyDemo demo = new MyDemo();
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.setContent(Thread.currentThread().getName() + "的数据");
                    System.out.println("-----------------------");
                    System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
                }
            });
            thread.setName("线程" + i);
            thread.start();
        }
    }
}

加锁是可以解决这个问题的,但是在这里我们强调的是线程数据隔离的问题,并不是多线程共享数据的问题, 在这个案例中使用synchronized关键字是不合适的。

和synchronized的区别

ThreadLocal 原理及例子

应用场景

需要在项目中进行数据传递线程隔离的场景,

在一些特定场景下,ThreadLocal方案有两个突出的优势:

  1. 传递数据 : 保存每个线程绑定的数据,在需要的地方可以直接获取, 避免参数直接传递带来的代码耦合问题

  2. 线程隔离 : 各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失

ThreadLocal 数据结构图示

ThreadLocal 原理及例子

​ 在ThreadLocalMap中,也是用Entry来保存K-V结构数据的。不过Entry中的key只能是ThreadLocal对象,这点在构造方法中已经限定死了。

​ 另外,Entry继承WeakReference,也就是key(ThreadLocal)是弱引用,其目的是将ThreadLocal对象的生命周期和线程生命周期解绑。

ThreadLocal 的内存泄漏

ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏。 

ThreadLocal 原理及例子

 同样假设在业务代码中使用完ThreadLocal ,栈区的threadLocal Ref被回收了。

​ 由于ThreadLocalMap只持有ThreadLocal的弱引用,没有任何强引用指向threadlocal实例, 所以threadlocal就可以顺利被gc回收,此时Entry中的key=null。

​ 但是在没有手动删除这个Entry以及CurrentThread依然运行的前提下,也存在有强引用链 threadRef->currentThread->threadLocalMap->entry -> value ,value不会被回收, 而这块value永远不会被访问到了,导致value内存泄漏。

​ 也就是说,ThreadLocalMap中的key使用了弱引用, 也有可能内存泄漏。
 

那么为什么key要用弱引用呢?

​ 事实上,在 ThreadLocalMap 中的  set/getEntry 方法中,会对key为null(也即是ThreadLocal为null)进行判断,如果为null的话,那么是会对value置为null的。

​ 这就意味着使用完ThreadLocal,CurrentThread依然运行的前提下,就算忘记调用remove方法,弱引用比强引用可以多一层保障:弱引用的ThreadLocal会被回收,对应的value在下一次ThreadLocalMap调用set,get,remove中的任一方法的时候会被清除,从而避免内存泄漏
 

弱引用

【Java虚拟机】弱引用引发的一些思考_Jungle_的博客-CSDN博客

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92839.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!