并发设计的思考

看了AtomicLong的实现或许会立马想到ReentrantLock或者Synchronized也可以实现原子类,只要在操作前获取锁,操作完释放锁。

但是为什么不用这些锁,而是用CAS呢?

显然,这些锁都是互斥锁,在多线程竞争激烈的情况下,伴随着大量线程上下文切换和独占,严重降低吞吐量。

然使用CAS + Volatile,这种乐观锁的机制,能使得线程Spin,并且可以并发读。这将会大幅度提升吞吐。

然而无论是互斥锁还是CAS + Volatile,它们本身都是一种锁机制。在严重竞争的情况下,都会有性能牺牲,比如大量的CAS失败,反复的Spin,消耗CPU资源。

在这种情况下,需要弄清楚竞争的资源是什么,是否可以将竞争点拆分,分摊压力。这种方式本质上是一种锁的粒度控制,将锁的粒度控制的更细,锁的范围更小。这种做法很多地方都有:

  1. ConcurrentHashMap中的实现,将对整个Map的锁,细化到对每个Segment上
  2. 如使用Synchronized或者ReentrantLock,尽量控制锁的范围,避免锁的范围
  3. Mysql的表锁和行锁设计,从MyISAM表锁到InnoDB支持行锁,将锁的粒度控制在行,从而提高存储引擎的并发

通过以上的优秀设计,可以总结出一套锁的优化思路:

互斥锁 -> 乐观锁 -> 锁的粒度控制

在Java中对应的实现方式:

ReentrantLock或者Syschronized -> CAS + Volatile -> 拆分竞争点

posted @ 2023-05-16 16:08  r1-12king  阅读(14)  评论(0编辑  收藏  举报