栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程

ThreadLocal 作用

很多地方叫做线程本地变量,也有些地方叫做线程本地存储,ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度

ThreadLocalMap(线程的一个属性)
  1. 每个线程中都有一个自己的 ThreadLocalMap 类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
  2. 将一个共用的 ThreadLocal 静态实例作为 key,将不同对象的引用保存到不同线程的ThreadLocalMap 中,然后在线程执行的各处通过这个静态 ThreadLocal 实例的 get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
  3. ThreadLocalMap 其实就是线程里面的一个属性,它在 Thread 类中定义ThreadLocal.ThreadLocalMap threadLocals = null
使用场景

最常见的 ThreadLocal 使用场景为 用来解决 数据库连接、Session 管理等。

内存溢出

ThreadLocal变量是维护在Thread内部的,这样的话只要我们的线程不退出,对象的引用就会 一直存在。当线程退出时,Thread类会进行一些清理工作,其中就包含ThreadLocalMap;ThreadLocal在没有线程池使用的情况下,正常情况下不会存在内存泄露,但是如果使用了线程 池的话,就依赖于线程池的实现,如果线程池不销毁线程的话,那么就会存在内存泄露。
当我们使用线程池的时候,就意味着当前线程未必会退出(比如固定大小的线程池,线程总是存
在的)。如果这样的话,将一些很大的对象设置到ThreadLocal中(这个很大的对象实际保存在Thread
的threadLocals属性中),这样的话就可能会出现内存溢出的情况。

变量副本维护

在ThreadLocal类中有一个static声明的Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。

内存回收
  • 在 ThreadLocal 层面的内存回收
    当线程死亡时,那么所有的保存在的线程局部变量就会被回收,其实这里是指线程Thread对象中的ThreadLocal.ThreadLocalMap threadLocals 会被回收,这是显然的。
  • ThreadLocalMap 层面的内存回收:
    如果线程可以活很长的时间,并且该线程保存的线程局部变量有很多(也就是 Entry 对象很多),那么就涉及到在线程的生命期内如何回收 ThreadLocalMap 的内存了,不然的话,Entry对象越多,那么ThreadLocalMap 就会越来越大,占用的内存就会越来越多,所以对于已经不需要了的线程局部变量,就应该清理掉其对应的Entry对象。
    使用的方式是,Entry对象的key是WeakReference 的包装,当ThreadLocalMap 的 private Entry[]table ,已经被占用达到了三分之二时 threshold = 2/3 (也就是线程拥有的局部变量超过了10个) ,就会尝试回收 Entry 对象,
总结

通过源代码可以看到每个线程都可以独立修改属于自己的副本而不会互相影响,从而隔离了线程和线程.避免了线程访问实例变量发生安全问题. 同时我们也能得出下面的结论:
(1)ThreadLocal只是操作Thread中的ThreadLocalMap对象的集合;
(2)ThreadLocalMap变量属于线程的内部属性,不同的线程拥有完全不同的ThreadLocalMap变量;
(3)线程中的ThreadLocalMap变量的值是在ThreadLocal对象进行set或者get操作时创建的;
(4)使用当前线程的ThreadLocalMap的关键在于使用当前的ThreadLocal的实例作为key来存储value值;
(5) ThreadLocal模式至少从两个方面完成了数据访问隔离,即纵向隔离(线程与线程之间的ThreadLocalMap不同)和横向隔离(不同的ThreadLocal实例之间的互相隔离);
(6)一个线程中的所有的局部变量其实存储在该线程自己的同一个map属性中;
(7)线程死亡时,线程局部变量会自动回收内存;
(8)线程局部变量时通过一个 Entry 保存在map中,该Entry 的key是一个 WeakReference包装的ThreadLocal, value为线程局部变量,key 到 value 的映射是通过:ThreadLocal.threadLocalHashCode & (INITIAL_CAPACITY - 1) 来完成的;
(9)当线程拥有的局部变量超过了容量的2/3(没有扩大容量时是10个),会涉及到ThreadLocalMap中Entry的回收;
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/683634.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号