美文网首页
浅谈ThreadLocal

浅谈ThreadLocal

作者: Android程序员老鸦 | 来源:发表于2023-08-14 17:00 被阅读0次

导读:ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本。通过ThreadLocal可以将对象的可见范围限制在同一个线程内。

ThreadLocal介绍&跳出误区

  • 跳出误区

需要重点强调的的是,不要拿ThreadLocal和synchronized做类比,因为这种比较压根就是无意义的!sysnchronized是一种互斥同步机制,是为了保证在多线程环境下对于共享资源的正确访问。而ThreadLocal从本质上讲,无非是提供了一个“线程级”的变量作用域,它是一种线程封闭(每个线程独享变量)技术,更直白点讲,ThreadLocal可以理解为将对象的作用范围限制在一个线程上下文中,使得变量的作用域为“线程级”。

没有ThreadLocal的时候,一个线程在其声明周期内,可能穿过多个层级,多个方法,如果有个对象需要在此线程周期内多次调用,且是跨层级的(线程内共享),通常的做法是通过参数进行传递;而ThreadLocal将变量绑定在线程上,在一个线程周期内,无论“你身处何地”,只需通过其提供的get方法就可轻松获取到对象。极大地提高了对于“线程级变量”的访问便利性。

  • 案例分享

假设我们要为每个线程关联一个唯一的序号,在每个线程周期内,我们需要多次访问这个序号,这时我们就可以使用ThreadLocal了.(当然下面这个例子没有完全体现出跨层级跨方法的调用,理解就可以了)

[图片上传失败...(image-59c474-1692089962065)]

执行结果,可以看到每个线程都分配到了一个唯一的ID,同时在此线程范围内的"任何地点",我们都可以通过ThreadId.get()这种方式直接获取。

[图片上传失败...(image-bce17a-1692089962065)]

看看源码

set操作,为线程绑定变量

[图片上传失败...(image-9dede3-1692089962065)]

可以看到,ThreadLocal不过是个入口,真正的变量是绑定在线程上的。

[图片上传失败...(image-32ad5a-1692089962065)]

下面给是Thread类中的定义,每个线程对象都拥有一个ThreadLocalMap对象

 ThreadLocal.ThreadLocalMap threadLocals = null;

复制

现在,我们能看出ThreadLocal的设计思想了:

  • ThreadLocal仅仅是个变量访问的入口;
  • 每一个Thread对象都有一个ThreadLocalMap对象,这个ThreadLocalMap持有对象的引用;
  • ThreadLocalMap以当前的threadlocal对象为key,以真正的存储对象为value。get时通过threadlocal实例就可以找到绑定在当前线程上的对象。

乍看上去,这种设计确实有些绕。我们完全可以在设计成Map<Thread,T>这种形式,一个线程对应一个存储对象。ThreadLocal这样设计的目的主要有两个:

  • 可以保证当前线程结束时相关对象能尽快被回收;
  • ThreadLocalMap中的元素会大大减少,我们都知道map过大更容易造成哈希冲突而导致性能变差。

我们再来看看get方法

[图片上传失败...(image-5d9c12-1692089962065)]

setInitialValue

复制

[图片上传失败...(image-51e1bd-1692089962065)]

initialValue方法,默认是null,访问权限是protected,即允许重写。

protected T initialValue() {
         return null;
}

复制

谈到这儿,我们应该已经对ThreadLocal的设计目的及设计思想有一定的了解了。

线程独享变量?

还有一个会引起疑惑的问题,我们说ThreadLocal为每一个线程维护一个独立的变量副本,那么是不是说各个线程之间真正的做到对于对象的“完全自治”而不对其他线程的对象产生影响呢?其实这已经不属于对于ThreadLocal的讨论,而是你出于何种目的去使用ThreadLocal。如果我们为一个线程关联的对象是“完全独享”的,也就是每个线程拥有一整套的新的 栈中的对象引用+堆中的对象,那么这种情况下是真正的彻底的“线程独享变量”,相当于一种深度拷贝,每个线程自己玩自己的,对该对象做任何的操作也不会对别的线程有任何影响。

另一种更普遍的情况,所谓的独享变量副本,其实也就是每个线程都拥有一个独立的对象引用,而堆中的对象还是线程间共享的,这种情况下,自然还是会涉及到对共享资源的访问操作,依然会有线程不安全的风险。所以说,ThreadLocal无法解决线程安全问题。

所以,需不需要完全独享变量,进行完全隔离,就取决于你的应用场景了。可以想象,对象过大的时候,如果每个线程都有这么一份“深拷贝”,并发又比较大,对于服务器的压力自然是很大的。像web开发中的servlet,servlet是线程不安全的,一请求一线程,多个线程共享一个servlet对象;而早期的CGI设计中,N个请求就对应N个对象,并发量大了之后性能自然就很差。

[图片上传失败...(image-9f0bf-1692089962065)]

ThreadLocal在spring的事务管理,包括Hibernate的session管理等都有出现,在web开发中,有时会用来管理用户会话 HttpSession,web交互中这种典型的一请求一线程的场景似乎比较适合使用ThreadLocal,但是需要特别注意的是,由于此时session与线程关联,而tomcat这些web服务器多会采用线程池机制,也就是说线程是可复用的,所以在每一次进入的时候都需要重新进行set,或者在结束时及时remove。

相关文章

  • 深入JDK源码一:ThreadLocal

    浅谈ThreadLocal设计 初看ThreadLocal的源码的时候,觉得有几个地方比较晦涩,于是索性按照自己的...

  • ThreadLocal浅谈

    最近在工作中,有用到ThreadLocal类,在我的另外一篇博客中,也提到了一些: 那么,ThreadLocal到...

  • ThreadLocal浅谈

    前言 最近项目中经常用到了ThreadLocal,所以仔细研究一下这个类,以备以后复习。 threadLocals...

  • 浅谈 ThreadLocal

    有时,你希望将每个线程数据(如用户ID)与线程关联起来。尽管可以使用局部变量来完成此任务,但只能在本地变量存在时才...

  • 浅谈ThreadLocal

    在阅读JTA源码的时候,看到事务管理器的是有,遇到这样一段代码。 其中的TheadLocal引起了我的注意。 通过...

  • 浅谈ThreadLocal

    一、ThreadLocal是什么 ThreadLocal是线程本地存储变量,线程将一些变量存储在ThreadLoc...

  • 浅谈synchronized、Lock、ThreadLocal和

    1. 背景 在进行多线程编程时,最让人头痛的无非是线程安全问题,对共享资源的访问控制,如果稍加不注意就可能导致莫名...

  • ThreadLocal

    ThreadLocal 简介ThreadLocal 使用ThreadLocal 原理InheritableThre...

  • ThreadLocal

    ThreadLocal 由于 ThreadLocal 支持范型,如 ThreadLocal< StringBuil...

  • 精通Java并发 - ThreadLocal

    3. ThreadLocal[#3-threadlocal]3.1 ThreadLocal 常用方法[#31-th...

网友评论

      本文标题:浅谈ThreadLocal

      本文链接:https://www.haomeiwen.com/subject/gqjcmdtx.html