关于AQS(AbstractQueuedSynchronizer)中对中断的应用
来源:互联网 发布:中软国际java培训骗局 编辑:程序博客网 时间:2024/05/18 02:47
在阅读AbstractQueuedSynchronizer
源码的过程中,发现了大量对中断机制的使用,正好最近看了一些Java中断机制的理论,这篇文档就是要看看Doug Lea
是如何使用中断的。这篇文章是以前两篇文章为基础的:
尝试阅读ReentrantLock、AbstractQueuedSynchronizer源码(一)
尝试阅读ReentrantLock、AbstractQueuedSynchronizer源码(二)
一、谈谈对中断的理解
如何去中断一个正在执行的线程A?
方法1、直接终止线程A,不再运行
方法2、提出中断申请,线程A处理中断申请
对于方法1非常暴力,可能会导致数据的不一致性。同时也很不安全,就想我们借别人东西,首先要提出申请,能不能借到要看对方,不能直接去抢东西;
方法2就十分友好,线程A在收到中断申请后,只需在合适的时候处理中断即可,如果没有合适的时间点,甚至可以不处理。
如果A线程想中断B线程,可以通过interrupt()
方法来通知B线程(每个线程对象中有一个标识位来标识是否接受到中断请求),B线程可以通过isInterrupted()、interrupt()
来判断自己是否被申请中断。
interrupt()
:返回中断状态后,将中断状态清空
我们常见的Thread.sleep()
等可阻塞方法是通过抛出InterruptedException
来对中断申请做响应的
/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does not lose ownership of any monitors. * * @param millis * the length of time to sleep in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public static native void sleep(long millis) throws InterruptedException;
注释中说,如果有线程中断了当前线程,当抛出异常后,被中断线程的中断状态会被清空。
虽然Thread.sleep()
是本地方法,不过可以预测内存形如:
if (this.interrupted()) { ... throw new InterruptedException();}
二、AQS中对中断的处理
acquire()/
方法
在前两篇文章中我们详细分析了AQS的acquire()
方法,该方法忽略了对中断的响应,但是会把中断标识向上传递,传递给调用者,调用者可自旋判断中断状态。
acquireInterruptibly()/
方法
该方法对应中断请求的处理与前面说的Thread.sleep()
类型,清空中断标识,抛出InterruptedException
public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); }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 GC failed = false; return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
await()/
方法
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
这个方法就有点意思了,该方法对于中断的处理包括两种方式。第一种就是重新中断,不处理;另外一种就抛出InterruptedException
如果该线程已经被转移到了同步队列,则抛出InterruptedException
;否则重新中断
// 只有线程处于中断状态,才会调用此方法final boolean transferAfterCancelledWait(Node node) { // 用 CAS 将节点状态设置为 0 // 如果这步 CAS 成功,说明是 signal 方法之前发生的中断,因为如果 signal 先发生的话,signal 中会将 waitStatus 设置为 0 if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { // 将节点转移到同步队列,即使中断了,依然会转移到阻塞队列 enq(node); return true; } // CAS 失败,因为 signal 方法已经将 waitStatus 设置为了 0 // signal 方法会将节点转移到同步队列,但是可能还没完成,这边自旋等待其完成 while (!isOnSyncQueue(node)) Thread.yield(); return false;}
- 关于AQS(AbstractQueuedSynchronizer)中对中断的应用
- 关于AbstractQueuedSynchronizer(AQS)的简单理解
- AbstractQueuedSynchronizer(AQS)
- AbstractQueuedSynchronizer(AQS)
- AbstractQueuedSynchronizer(AQS)源码解析(一)
- 【Java并发】- AbstractQueuedSynchronizer详解(AQS)
- AQS(AbstractQueuedSynchronizer)源码分析
- AbstractQueuedSynchronizer源码剖析(三)- 响应中断的独占锁
- AbstractQueuedSynchronizer源码剖析(五)- 响应中断的共享锁
- Java中的锁 (3) 同步器AQS (AbstractQueuedSynchronizer)
- 【java基础】线程笔记——AQS(AbstractQueuedSynchronizer)
- JUC - AbstractQueuedSynchronizer(AQS) 源码分析
- AbstractQueuedSynchronizer(AQS)源码解析上
- AbstractQueuedSynchronizer(AQS)源码解析下
- AbstractQueuedSynchronizer(AQS)源码解析-续
- 关于AQS的学习(一)
- 关于AQS的一点总结
- AbstractQueuedSynchronizer的衍生品ReentrantLock(七)- 不响应中断的独占锁
- thymeleaf学习笔记
- unbuntn中使用密匙登录
- MySql 数据库逻辑架构
- PAT(Basic Level)1003 我要通过!
- 支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc
- 关于AQS(AbstractQueuedSynchronizer)中对中断的应用
- Ubuntu环境下安装Nginx+PHP7+MySQL图文教程
- Linux Setuid(SUID)和Setgid(SGID) sticky bit
- unbuntu中安装LNMP
- Windows命令行查看文件的MD5
- [Java]“语法糖”系列(三)之集合流操作(Stream)[笔记]
- springmvc和struts2的区别
- linux shell使用tar 备份时间命名的文件
- Unity 线性空间对ugui的影响