美文网首页
JUC包-001、谈JUC包锁设计的思路

JUC包-001、谈JUC包锁设计的思路

作者: Docker_Compose | 来源:发表于2021-07-22 21:56 被阅读0次

1、如何设计锁?

  设计一把锁,首先要解决以下四个问题:

(1)如何表示锁的状态?
# 记录锁的状态,无锁、有锁、可重入锁的次数
int states;

  一般来说,锁只有两种状态,一种是无锁,一种是有锁。因此,用布尔值来表示锁的状态即可,但是在JUC包中,却是int类型表示锁的状态,这是为何?

  在JUC包中,之所以用int 类型表示锁状态,是因为可重入锁的缘故。虽然定义多个布尔值类型同样可以解决可重入锁的问题,但是这就让代码冗余了,因此,选择int类型不禁是要记录无锁与有锁的状态,还要记录可重入的次数。


(2)如何保证多线程抢锁线程安全?
层面 机制
源码 CAS
JVM 屏障机制
硬件 lock cmpxchg

  要想回答这个问题,得从三个方面来谈,锁的源码,JVM层面以及CPU硬件层面。

  首先是源码,在源码中,就是CAS操作。其次则是JVM层,JVM提供了四种屏障机制,loadstore、storeload、loadload、storestore。最后是CPU硬件层面,以x64的英特尔的来说,它提供了一个指令lock cmpxchg。


(3)如何处理获取不到锁的线程?

  处理方式:自旋、阻塞、自旋+阻塞。

  自旋,线程获取不到锁,就一直占用CPU进行等待,直到获得锁;这种方式比较占用CPU资源,在CPU核数多线程并发高的情形下,会直接导致性能问题;因此,自旋的适用场景,线程争用少且代码量少的临界区。

  阻塞,线程尝试获取锁失败达到一定次数后,就告诉OS让其进行阻塞,从而进入到等待队列,直到被唤醒。


(4)如何释放锁?

  自旋:自个抢锁;阻塞:等待唤醒。



2、自旋与阻塞,哪一种锁等待方式更优?

  自旋与阻塞无优劣之分,它们有各自的适用场景。

  自旋,即线程抢不到锁,占用CPU自旋,直到抢到锁;阻塞,即线程抢不到锁,就让OS阻塞其,直到被唤醒。

  自旋适用于执行步骤少且快的操作,自旋一会儿就能马上获得锁,这样就不会占用太多的CPU的资源。这是自旋的优点。

  当CPU个数增加且线程数增加的情况下,自旋占用CPU,浪费资源,其的优点就会退化成缺点。在这种场景下,阻塞比自旋更有优势。



3、公平锁与非公平锁,哪个性能更优?

  公平锁,线程先查看等待队列中有没有线程,如果有,那么就进入等待队列,如果没有,则进行抢锁。这一过程,就会产生线程上下文切换时间和调度延迟的时间。

  非公平锁,线程不管等待队列中有没有线程,率先抢锁,抢锁失败,再进入等待队列。这一过程,同样会产生线程上下文切换时间和调度延迟的时间,但是并非绝对的,因为一旦抢锁成功,就会有这两个时间了。

  因此,非公平锁的性能优于公平锁。

相关文章

网友评论

      本文标题:JUC包-001、谈JUC包锁设计的思路

      本文链接:https://www.haomeiwen.com/subject/ljrapltx.html