ZKX's LAB

聊一聊面试常见的ThreadLocal问题

2020-11-26新闻8

短小而精悍,简单易懂,每天Look一眼,增长技术实力。

先简单描述一下:

ThreadLoal线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本

Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用

Thread 有自己的实例副本,不存在多线程间共享的问题

ThreadLocal 变量通常被private static修饰,当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收

总体描述一下使用场景:

每个线程需要有自己单独的实例

实例需要在多个方法中共享,但不希望被多线程共享

举个例子:Java7 中的SimpleDateFormat不是线程安全的,可以用ThreadLocal来解决这个问题

(java8中的DateTimeFormatter是线程安全的)

谈谈一下内部原理:也就是面试的时候喜欢问的东东

首先明确一点 ThreadLocal 是一个泛型类,保证可以接受任何类型的对象

ThreadLocal 内部维护了一个 Map 注意下的是 该 Map 不是 HashMap 而是ThreadLocalMap ,它是一个静态内部类

ThreadLocal 方法 get() ,set(),remove()方法其实调用的是内部ThreadLocalMap对应的方法,外面其实是一个引用壳,传递方法引用

简单Look一下源码加深一下记忆

源码对应的set方法

源码对应的get方法

咱接着谈一下 使用场景注意的地方 内存泄漏 (上面都是常识的话,这里就是使用经验)

ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用(弱引用特点,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉)

ThreadLocal 内部的 value 是强引用,不会被清理,这样一来就有可能出现 key 为 null 的 value 也就是此处会有可能造成内存泄漏的情况

ThreadLocal设计维护还是挺不错的,充分考虑到了这一点,在使用set(),get(),remove()方法的时候 内部会做一次扫描检测,如果存在key为null的情况会自动回收

基于以上特点所以在使用的时候规范一下 :避免这种情况的出现要主动调用remove()方法启动内部循环检测,清除无效数据。使用 try-finally 块进行回收,在finally中,主动调用该对象的remvoe()方法。

最后再简单看一下类 ThreadLocalRandom

ThreadLocalRandom使用ThreadLocal的原理,让每个线程内持有一个本地的种子变量,该种子变量只有在使用随机数时候才会被初始化,多线程下计算新种子时候是根据自己线程内维护的种子变量进行更新,从而避免了竞争

#技术编程

随机阅读

qrcode
访问手机版