上次分析了ReentrantLock#lock()与ReentrantLock#unlock()的实现原理,并初步讨论了AQS的等待队列模型,参考源码|并发一枝花之ReentrantLock与AQS(1):lock、unlock。

本文继续分析ReentrantLock#lockInterruptibly(),内容简单,可以跳过。

JDK版本:oracle java 1.8.0_102

接口声明

public interface Lock {...void lock();void lockInterruptibly() throws InterruptedException;void unlock();...
}
复制代码

Lock#lockInterruptibly()是Lock#lock()的一个衍生品,解锁方法也为Lock#unlock()。因此,我们只需要分析Lock#lockInterruptibly()。

功能

Lock#lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。

一个典型用法如下:

当两个线程同时通过Lock#lockInterruptibly()阻塞的获取某个锁时,假如此时线程A获取到了锁,则线程B只有继续等待;此时,让线程A对线程B调用threadB.interrupt()方法,能够中断线程B的等待,让线程B可以先做其他事。

想对的,如果使用内置锁synchronized,当一个线程处于等待某个锁的状态时,是无法被中断的,只有一直等待下去。这是可中断锁最大的优势。

注意,当一个线程获取了锁之后,是不会被Thread#interrupt()方法中断的。

实现原理

基本的实现原理与ReentrantLock#lock()相同。

仍以默认的非公平策略为例进行分析。

lockInterruptibly

    public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}
复制代码

回忆ReentrantLock的核心思想:用state表示“所有者线程已经重复获取该锁的次数”

acquireInterruptibly

public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplements java.io.Serializable {...public final void acquireInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (!tryAcquire(arg))doAcquireInterruptibly(arg);}...
}
复制代码

改写:

public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplements java.io.Serializable {...public final void acquireInterruptibly(int arg)if (Thread.interrupted())throw new InterruptedException();if (tryAcquire(arg)) {return;}doAcquireInterruptibly(arg);}...
}
复制代码

首先,通过tryAcquire()尝试获取锁。如果获取成功,则直接返回。如果获取失败,则借助doAcquireInterruptibly实现可中断获取。

NonfairSync#tryAcquire()在ReentrantLock#lock()中分析过了,直接看AQS#doAcquireInterruptibly()。

doAcquireInterruptibly

public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplements java.io.Serializable {...private void doAcquireInterruptibly(int arg)throws InterruptedException {final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}...
}
复制代码

同AQS#acquireQueued()基本相同,唯一的区别是对中断信号的处理。

AQS#acquireQueued()被中断后,将中断标志传给外界,外界再调用Thread#interrupt()复现中断;而AQS#doAcquireInterruptibly()则直接抛出InterruptedException。

二者本质上没什么不同。但AQS#doAcquireInterruptibly()显示抛出了InterruptedException,调用者必须处理或继续上抛该异常。

总结

可以看到,分析完ReentrantLock#lock()后,其衍生品ReentrantLock#lockInterruptibly()的分析也变得极其简单。ReentrantLock#tryLock()与之相似,不再分析。


本文链接:源码|并发一枝花之ReentrantLock与AQS(2):lockInterruptibly
作者:猴子007
出处:monkeysayhi.github.io
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名及链接。

源码|并发一枝花之ReentrantLock与AQS(2):lockInterruptibly相关推荐

  1. 源码|并发一枝花之ReentrantLock与AQS(3):Condition

    ReentrantLock#lock().ReentrantLock#unlock().ReentrantLock#lockInterruptibly()的分析见前文: 源码|并发一枝花之Reentr ...

  2. 源码|并发一枝花之CopyOnWriteArrayList

    CopyOnWriteArrayList的设计思想非常简单,但在设计层面有一些小问题需要注意. JDK版本:oracle java 1.8.0_102 本来不想写的,但是github上CopyOnWr ...

  3. 源码|并发一枝花之ConcurrentLinkedQueue

    首先声明,本文是伪源码分析.主要是基于状态机自己实现一个简化的并发队列,有助于读者掌握并发程序设计的核心--状态机:最后对源码实现略有提及. ConcurrentLinkedQueue不支持阻塞,没有 ...

  4. 源码|并发一枝花之ConcurrentLinkedQueue【伪】

    首先声明,本文是伪源码分析.主要是基于状态机自己实现一个简化的并发队列,有助于读者掌握并发程序设计的核心--状态机:最后对源码实现略有提及. ConcurrentLinkedQueue不支持阻塞,没有 ...

  5. 源码|并发一枝花之BlockingQueue

    今天来介绍Java并发编程中最受欢迎的同步类--堪称并发一枝花之BlockingQueue. JDK版本:oracle java 1.8.0_102 继续阅读之前,需确保你对锁和条件队列的使用方法烂熟 ...

  6. Java 并发编程CyclicBarrier的应用与源码解析(基于ReentrantLock实现)

    什么是CyclicBarrier? CyclicBarrie和上一篇中讲到CountDownLatch很类似,它能阻塞一组线程直到某个事件的发生. 栅栏与闭锁的关键区别在于:所有必须同时到达栅栏位置才 ...

  7. 从源码角度彻底理解ReentrantLock(重入锁)

    源码分析ReentrantLock https://blog.csdn.net/lxltmac/article/details/84871929白话讲解lock

  8. 并发读源码——并发读源码Striped64/LongAdder/DoubleAdder/LongAccumulator/DoubleAccumulator

    文章目录 1.LongAdder原理介绍 2.LongAdder源码介绍 3.LongAdder并发时应用 4.DoubleAdder分析 5.LongAccumulator分析 6.DoubleAc ...

  9. 02.2跟雨痕看go源码- 并发清理与三色标记

    据说这是go优化最狠的地方. http://blog.csdn.net/erlib/article/details/51850912 大意是说twitch.tv觉得一次标记的STW(stop the ...

最新文章

  1. ubuntu ssh 客户端查看服务器端图形界面
  2. 伟大的密码胜于利剑——RSA2012成都站掠影
  3. 谷歌chrome浏览器的源码分析(四)
  4. 电脑分辨率设置工具_干货分享:PPT 导出高清分辨率图片的四种方法
  5. mock 测试 MVC
  6. get assigned pageset and my pages
  7. Delphi编程禁止用户关闭操作系统
  8. 程序员如何面对 HR 面试的 40 个问题
  9. [转载]Python量化交易平台开发教程系列0-引言
  10. 大数据之HBase教程
  11. 华为Mate 40系列外观偷跑:后置八卦图六摄亮了!
  12. 22.使用非阻塞IO 1
  13. 电大计算机应用基础考试题6,2016电大计算机应用基础考试题及答案.doc
  14. matlab读取写音频文件
  15. 王道计算机考研——计算机组成原理笔记
  16. 『实用教程』四种超实用的超级记忆法以及记忆训练案例
  17. CentOS官网下载对应版本
  18. 分布式系统的SLA如何定义
  19. 什么查重软件比较好用?
  20. 用函数统计各分数段人数c语言,如何使用Excel函数统计各分数段的人数(五种方法)...

热门文章

  1. 水下航行器-动力控制篇
  2. centos7安装nvida显卡驱动
  3. python+tkinter桌面时钟
  4. ROS机器人Diego 1#制作(三)base controller---ros_arduino_bridge
  5. UG NX二次开发(C#)-文件-导出图像
  6. 世纪TV显示连接服务器错误,TV-Anytime服务器网络中一个映射问题的启发式算法
  7. 【妖精的尾巴win7动漫主题】
  8. kafka远离_在远离社会的时代如何保持生产力
  9. 【源码】IEEE 14总线系统模型
  10. 三阶四阶魔方自动复原程序(Java)