快捷搜索:

01_使用并发工具类库,线程安全就高枕无忧了吗

I. 使用并发工具类库问题

1.没有意识到线程重用导致用户信息错乱的 Bug

一是,只知道使用并发工具,但并不清楚当前线程的来龙去脉,解决多线程问题却不了解线程。比如,使用 ThreadLocal 来缓存数据,以为 ThreadLocal 在线程之间做了隔离不会有线程安全问题,没想到线程重用导致数据串了。请务必记得,在业务逻辑结束之前清理 ThreadLocal 中的数据。

2.使用了线程安全的并发工具,并不代表解决了所有线程安全问题

二是,误以为使用了并发工具就可以解决一切线程安全问题,期望通过把线程不安全的类替换为线程安全的类来一键解决问题。比如,认为使用了 ConcurrentHashMap 就可以解决线程安全问题,没对复合逻辑加锁导致业务逻辑错误。如果你希望在一整段业务逻辑中,对容器的操作都保持整体一致性的话,需要加锁处理。

3.没有充分了解并发工具的特性,从而无法发挥其威力

三是,没有充分了解并发工具的特性,还是按照老方式使用新工具导致无法发挥其性能。比如,使用了 ConcurrentHashMap,但没有充分利用其提供的基于 CAS 安全的方法,还是使用锁的方式来实现逻辑。

4.没有认清并发工具的使用场景,因而导致性能问题

四是,没有了解清楚工具的适用场景,在不合适的场景下使用了错误的工具导致性能更差。比如,没有理解 CopyOnWriteArrayList 的适用场景,把它用在了读写均衡或者大量写操作的场景下,导致性能问题。对于这种场景,你可以考虑是用普通的 List。

II.补充知识

1.ThreadLocalRandom,你觉得是否可以把它的实例设置到静态变量中,在多线程情况下重用呢?

不可以。ThreadLocalRandom类中只封装了一些公用的方法,种子存放在各个线程中。ThreadLocalRandom中存放一个单例的instance,调用current()方法返回这个instance,每个线程首次调用current()方法时,会在各个线程中初始化seed和probe。nextX()方法会调用nextSeed(),在其中使用各个线程中的种子,计算下一个种子并保存。所以,如果使用静态变量,直接调用nextX()方法就跳过了各个线程初始化的步骤,只会在每次调用nextSeed()时来更新种子。

2.说说ConcurrentHashMap 中 computeIfAbsent 和 putIfAbsent 方法的区别?

a.参数不一样,putIfAbsent是值,computeIfAbsent是mappingFunction b.返回值不一样,putIfAbsent是之前的值,computeIfAbsent是现在的值

3.相同线程的不同逻辑需要共享数据(但又无法通过传值来共享数据),或为了避免相同线程重复创建对象希望重用数据,可以考虑使用ThreadLocal

经验分享 程序员 职场和发展