王者并发课-铂金3:一劳永逸-如何理解锁的多次可重入问题

欢迎来到《王者并发课》,本文是该系列文章中的第16篇

在前面的文章《铂金1:探本溯源-为何说Lock接口是Java中锁的基础》中,我们提到了锁的可重入问题,并作了简单介绍。鉴于锁的可重入是一个重要概念,所以本文把拿出来做一次单独讲解,以帮助你彻底理解它。

一、锁的可重入所造成的问题

首先,我们通过一段示例代码看锁的可重入是如何导致问题发生,以理解它的重要性。

public class ReentrantWildArea {     // 野区锁定     private boolean isAreaLocked = false;      // 进入野区A     public synchronized void enterAreaA() throws InterruptedException {         isAreaLocked = true;         System.out.println("已经进入野区A...");         enterAreaB();     }     // 进入野区B     public synchronized void enterAreaB() throws InterruptedException {         while (isAreaLocked) {             System.out.println("野区B方法进入等待中...");             wait();         }         System.out.println("已经进入野区B...");     }      public synchronized void unlock() {         isAreaLocked = false;         notify();     } } 

在上面这段代码中,我们创建了一片野区,包含了野区A野区B。接着,我们再创建一个打野英雄铠,让他进去野区打野,看看会发生什么事情。

public static void main(String[] args) {   // 打野英雄铠进入野区   Thread kaiThread = new Thread(() -> {     ReentrantWildArea wildArea = new ReentrantWildArea();     try {       wildArea.enterAreaA();     } catch (InterruptedException e) {       e.printStackTrace();     }   });   kaiThread.start(); } 

输出结果如下:

已经进入野区A... 野区B方法进入等待中... 

从结果中可以看到,虽然在同一块野区,但是铠只进入野区A,却没能进入野区B,被阻塞在半道上了。从代码分析上看,野区的两个方法都声明了synchronized,但铠在进入野区A之后,野区进行了锁定isAreaLocked = true,导致铠进入野区B时失败。

这就是典型的锁的可重入所造成的问题。在并发编程时,如果未能处理好这一问题,将会造成线程的无限阻塞,其后果和死锁相当

二、理解锁的可重入

所谓锁的可重入,指的是锁可以被线程 重复递归 调用,也可以理解为对同一把锁的重复获取。 如果未能处理好锁的可重入问题,将会导致和死锁类似的问题。

王者并发课-铂金3:一劳永逸-如何理解锁的多次可重入问题

三、如何避免锁的可重入问题

避免锁的可重入问题,需要注意两个方面:

  • 尽量避免编写需要重入获取锁的代码
  • 如果需要,使用可重入锁

在Java中,synchronized是可以重入的,下面的这段代码在调用时不会产生重入问题。

public class WildMonster {     public synchronized void A() {         B();     }          public synchronized void B() {        doSomething...     } }  

但是,基于Lock接口所实现的各种锁并不总是支持可重入的。在前面的文章中,我们已经展示过不支持重入的Lock接口实现。在具体的场景中使用时,需要务必注意这点。如果需要可重入锁,可以使用Java中的ReentrantLock类。

小结

在本文中,我们再次介绍了锁的可重入问题,并介绍了其产生的原因及避免方式。Java中的synchronized关键字支持锁的可重入,但是其他显示锁并非总是支持这一特性,在使用时需要注意。

此外,需要注意的是,锁的可重入对锁的性能有一定的影响,而且实现起来更为复杂。所以,我们不能说锁的可重入与不可重入哪个好,这要取决于具体的问题

正文到此结束,恭喜你又上了一颗星✨

夫子的试炼

  • 查看ReentrantLock源码,了解其支持可重入的原理。

延伸阅读与参考资料

关于作者

从业近十年,先后从事敏捷与DevOps咨询、Tech Leader和管理等工作,对分布式高并发架构有丰富的实战经验。热衷于技术分享和特定领域书籍翻译,掘金小册《高并发秒杀的设计精要与实现》作者。


关注公众号【MetaThoughts】,及时获取文章更新和文稿。

如果本文对你有帮助,欢迎点赞关注监督,我们一起从青铜到王者

发表评论

相关文章