今天小编给大家分享一下Java多线程之ThreadLocal的原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。ThreadLocal,即线程本地变量,如果你创建了一个变量,那么访问这个变量的每个线程都会有这个变量的本地拷贝,多个线程操作这个变量的时候,实际操作自己本地内存里面的变量,从而起到线程隔离的作用,避免了线程安全问题ThreadLocal 适用于无状态,副本变量独立后不影响业务逻辑的高并发场景,如果业务逻辑强依赖于变量副本,则不适合用 ThreadLocal 解决,需要另寻解决方案应用场景:数据库连接池会话管理中使用在 JDK8 中,每个线程 Thread 内部都维护了一个 ThreadLocalMap 的数据结构,ThreadLocalMap 中有一个由内部类 Entry 组成的 table 数组,Entry 的 key 就是线程的本地化对象 ThreadLocal,而 value 则存放了当前线程所操作的变量副本。每个 ThreadLocal 只能保存一个副本 value,并且各个线程的数据互不干扰,如果想要一个线程保存多个副本变量,就需要创建多个ThreadLocal。一个 ThreadLocal 的值,会根据线程的不同,分散在 N 个线程中,所以获取 ThreadLocal 的 value,有两个步骤:第一步,根据线程获取 ThreadLocalMap第二步,根据自身从 ThreadLocalMap 中获取值,所以它的 this 就是 Map 的 Key当执行 set() 方法时,其值是保存在当前线程的 ThreadLocal 变量副本中
当执行get() 方法中,是从当前线程的 ThreadLocal 的变量副本获取。所以对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了线程的隔离,互不干扰。ThreadLocal 对外暴露的方法有4个:1.initialValue()方法:返回为当前线程初始副本变量值。
2.get()方法:获取当前线程的副本变量值。
3.set()方法:保存当前线程的副本变量值。
4.remove()方法:移除当前前程的副本变量值执行流程:1.获得当前线程,根据当前线程获得 map。
2.如果 map 不为空,则将参数设置到 map 中,当前的 Threadlocal 作为 key。
3.如果 map 为空,则给该线程创建 map,设置初始值。执行流程:(1)先尝试获得当前线程,再根据当前线程获取对应的 map
(2)如果获得的 map 不为空,以当前 threadlocal 为 key 尝试获得 entry
(3)如果 entry 不为空,返回值。
(4)如果 2 跟 3 出现无法获得,则通过 initialValue 函数获得初始值,然后给当前线程创建新 map执行流程:首先尝试获取当前线程,然后根据当前线程获得map,从map中尝试删除enrty。执行流程:(1)如果没有调用 set() 直接 get(),则会调用此方法,该方法只会被调用一次,
(2)默认返回一个缺省值null,如果不想返回null,可以Override 进行覆盖。和 HashMap 不同,ThreadLocalMap 结构中没有 next 引用
ThreadLocalMap 中解决哈希冲突的方式并非链表的方式,而是采用线性探测的方式,当发生哈希冲突时就将步长加1或减1,寻找下一个相邻的位置流程说明:1.根据 ThreadLocal 对象的 hash 值,定位到 table 中的位置 i;2.如果当前位置是 null,就初始化一个 Entry 对象放在位置 i 上;3.如果位置 i 已经有 Entry 对象了,如果这个 Entry 对象的 key 与即将设置的 key 相同,那么重新设置 Entry 的 value;4.如果位置 i 的 Entry 对象和 即将设置的 key 不同,那么寻找下一个空位置;在使用 ThreadLocal 时,当使用完变量后,必须手动调用 remove() 方法删除 entry 对象,否则会造成 value 的内存泄露,严格来说,ThreadLocal 是没有内存泄漏问题,有的话,那也是忘记执行 remove() 引起的内存泄露的根本原因在于 ThreadLocalMap 的生命周期与当前线程 CurrentThread 的生命周期相同,且 ThreadLocal 使用完没有进行手动删除导致的ThreadLocal 的内存泄露与强弱引用无关,那么为什么还要用弱引用呢?(1)Entry 中的 key(Threadlocal)是弱引用,目的是将 ThreadLocal 对象的生命周期跟线程周期解绑,用 WeakReference 弱引用关联的对象,只能生存到下一次垃圾回收之前,GC发生时,不管内存够不够,都会被回收。(2)当我们使用完 ThreadLocal,而 Thread 仍然运行时,即使忘记调用 remove() 方法, 弱引用也会比强引用多一层保障:当 GC 发生时,弱引用的 ThreadLocal 被收回,那么 key 就为 null 了。而 ThreadLocalMap 中的 set()、get() 方法,会针对 key == null (也就是 ThreadLocal 为 null) 的情况进行处理,如果 key == null,则系统认为 value 也应该是无效了应该设置为 null,也就是说对应的 value 会在下次调用 ThreadLo免费云主机域名cal 的 set()、get() 方法时,执行底层 ThreadLocalMap 中的 expungeStaleEntry() 方法进行清除无用的 value,从而避免内存泄露。(1)Hibernate 的 session 获取:每个线程访问数据库都应当是一个独立的 session 会话,如果多个线程共享同一个 session 会话,有可能其他线程关闭连接了,当前线程再执行提交时就会出现会话已关闭的异常,导致系统异常。使用 ThreadLocal 的方式能避免线程争抢session,提高并发安全性。(2)Spring 的事务管理:事务需要保证一组操作同时成功或失败,意味着一个事务的所有操作需要在同一个数据库连接上,Spring 采用 Threadlocal 的方式,来保证单个线程中的数据库操作使用的是同一个数据库连接,同时采用这种方式可以使业务层使用事务时不需要感知并管理 connection 对象,通过传播级别,巧妙地管理多个事务配置之间的切换,挂起和恢复使用 InheritableThreadLocal 可以实现多个线程访问 ThreadLocal 的值我们在主线程中创建一个 InheritableThreadLocal 的实例,然后在子线程中得到这个InheritableThreadLocal实例设置的值。ThreadLocal 能实现线程的数据隔离,不在于它自己本身,而在于 Thread 的 ThreadLocalMap,所以,ThreadLocal 可以只实例化一次,只分配一块存储空间就可以了,没有必要作为成员变量多次被初始化。以上就是“Java多线程之ThreadLocal的原理是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注百云主机行业资讯频道。
本文小编为大家详细介绍“ReactRenderProps模式如何运用”,内容详细,步骤清晰,细节处理妥当,希望这篇“ReactRenderProps模式如何运用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。上代码:结果很简单就能猜到…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。