`
森林的天空
  • 浏览: 15266 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JAVA并发编程学习笔记之AQS源码分析(超时、中断与其他)

 
阅读更多

(非原创)

中断

JAVA中并没有好的中断线程的方式,早期引入的Thead.stop()和Thread.resume()容易导致死锁(参考:http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html),已经不推荐使用。

JAVA线程提供了协作式中断,何为协作是中断,是相对抢占式中断而言的,简单来讲就是设置一个中断标志位,不停地检查这个标志位的状态,如果检查到线程中断,就中断线程。JVM线程内部维护着一个中断标志,程序员不能直接操作这个中断标志位,只能通过线程的以下几个方法设置中断位:

 

  1. public void interrupt()  
  2. public static boolean interrupted()   
  3. private native boolean isInterrupted(boolean ClearInterrupted);  
  4. public boolean isInterrupted()  

 

AQS中提供了支持中断的方法

 

  1. private void doAcquireInterruptibly(int arg) throws InterruptedException;  
  2. private void doAcquireSharedInterruptibly(int arg) throws InterruptedException;   
  3. private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException;  

这几个方法都抛出了InterruptedException,这些方法都会先出处中断异常,处理的代码如下:

 

 

  1. if (Thread.interrupted())  
  2.     throw new InterruptedException();  

我们还看到有些方法并没有申请抛出InterruptedException,当它被中断时,设置了线程的中断位。

 

 

  1. private static void selfInterrupt() {  
  2.     Thread.currentThread().interrupt();  
  3. }  

超时

AQS与JVM内置锁的一个不同点在于AQS中提供了超时机制,即线程在等待一定时间后会立即返回。下面以doAcquireNanos为例来分析:
  1. private boolean doAcquireNanos(int arg, long nanosTimeout)  
  2.     throws InterruptedException {  
  3.     long lastTime = System.nanoTime();  
  4.     final Node node = addWaiter(Node.EXCLUSIVE);  
  5.     boolean failed = true;  
  6.     try {  
  7.         for (;;) {  
  8.             final Node p = node.predecessor();  
  9.             if (p == head && tryAcquire(arg)) {  
  10.                 setHead(node);  
  11.                 p.next = null// help GC  
  12.                 failed = false;  
  13.                 return true;  
  14.             }  
  15.             if (nanosTimeout <= 0)  
  16.                 return false;  
  17.             if (shouldParkAfterFailedAcquire(p, node) &&  
  18.                 nanosTimeout > spinForTimeoutThreshold)  
  19.                 LockSupport.parkNanos(this, nanosTimeout);  
  20.             long now = System.nanoTime();  
  21.             nanosTimeout -= now - lastTime;  
  22.             lastTime = now;  
  23.             if (Thread.interrupted())  
  24.                 throw new InterruptedException();  
  25.         }  
  26.     } finally {  
  27.         if (failed)  
  28.             cancelAcquire(node);  
  29.     }  
  30. }  
1、首先取得当前系统时间,在循环等待的过程中,如果剩余时间<=0立即返回;
2、如果剩余时间>0,就用总时间减去一次循环耗费的时间,继续阻塞;
3、如果在这期间线程被中断,就抛出中断异常,如果有其他异常产生,就取消这次获取。
 

取消

取消获取的逻辑比较复杂,下面来分析一下:
  1. private void cancelAcquire(Node node) {  
  2.       // Ignore if node doesn't exist  
  3.       if (node == null)  
  4.           return;  
  5.   
  6.       node.thread = null;  
  7.   
  8.       // Skip cancelled predecessors  
  9.       Node pred = node.prev;  
  10.       while (pred.waitStatus > 0)  
  11.           node.prev = pred = pred.prev;  
  12.   
  13.       // predNext is the apparent node to unsplice. CASes below will  
  14.       // fail if not, in which case, we lost race vs another cancel  
  15.       // or signal, so no further action is necessary.  
  16.       Node predNext = pred.next;  
  17.   
  18.       // Can use unconditional write instead of CAS here.  
  19.       // After this atomic step, other Nodes can skip past us.  
  20.       // Before, we are free of interference from other threads.  
  21.       node.waitStatus = Node.CANCELLED;  
  22.   
  23.       // If we are the tail, remove ourselves.  
  24.       if (node == tail && compareAndSetTail(node, pred)) {  
  25.           compareAndSetNext(pred, predNext, null);  
  26.       } else {  
  27.           // If successor needs signal, try to set pred's next-link  
  28.           // so it will get one. Otherwise wake it up to propagate.  
  29.           int ws;  
  30.           if (pred != head &&  
  31.               ((ws = pred.waitStatus) == Node.SIGNAL ||  
  32.                (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&  
  33.               pred.thread != null) {  
  34.               Node next = node.next;  
  35.               if (next != null && next.waitStatus <= 0)  
  36.                   compareAndSetNext(pred, predNext, next);  
  37.           } else {  
  38.               unparkSuccessor(node);  
  39.           }  
  40.   
  41.           node.next = node; // help GC  
  42.       }  
  43.   }  
1、首先取得当前结点的前趋结点,如果前趋结点也被取消直接跳过,继续向前找非取消的结点;
2、将当前结点设置为取消状态;
3、如果当前结点是队尾结点,则将当前结点从队尾移除;否则执行4;
4、找到当前结点的继任结点,前趋的next指针指向继任结点(pred->next=current->next);
5、当前结点的next指针指向自己,前面提到这一方面为了回收,一方面为了使isOnSyncQueue方法简单。
 

其他

AQS还提供了一些线程监控的方法:
  1. //获取哪些线程在等待  
  2. protected final Collection<Thread> getWaitingThreads();   
  3. //获取等待队列的长度  
  4. protected final int getWaitQueueLength();   
  5. //是否有线程在等待  
  6. protected final boolean hasWaiters()  
  7. //是否拥有同步器  
  8. final boolean isOwnedBy(AbstractQueuedSynchronizer sync)  
  9. //是否在同步队列中  
  10. final boolean isOnSyncQueue(Node node)  
  11. //支持共享模式的线程  
  12. public final Collection<Thread> getSharedQueuedThreads()  
  13. //支持独占模式的线程  
  14. public final Collection<Thread> getExclusiveQueuedThreads();  

参考资料:

 

分享到:
评论

相关推荐

    Java并发编程学习笔记

    Java并发编程是Java开发中必不可少的一部分,涉及到多线程、同步机制、线程池以及并发工具类等多个核心知识点。以下是对这些主题的详细说明: 1. **线程安全与锁 Synchronized 底层实现原理**: 线程安全是指在多...

    java并发编程:juc、aqs

    Java并发编程中的`JUC`(Java Util Concurrency)库是Java平台中用于处理多线程问题的核心工具包,它提供了一系列高效、线程安全的工具类,帮助开发者编写并发应用程序。`AQS`(AbstractQueuedSynchronizer)是JUC库中的...

    Java并发编程解析 | 解析AQS基础同步器的设计与实现

    "Java并发编程解析 | 解析AQS基础同步器的设计与实现" 在Java领域中,解决并发编程问题的关键是解决同步和互斥的问题。同步是指线程之间的通信和协作,互斥是指同一时刻只能允许一个线程访问共享资源。Java领域中有...

    Java 并发编程实战.pdf

    本书名为《Java 并发编程实战》,主要针对Java开发者,在内容上深入探讨了Java语言中的线程和并发编程机制。本书的描述表明了它将复杂的技术内容用浅显易懂的方式表达出来,使之成为读者在学习和使用Java进行并发...

    Java并发编程全景图.pdf

    Java并发编程是Java语言中最为复杂且重要的部分之一,它涉及了多线程编程、内存模型、同步机制等多个领域。为了深入理解Java并发编程,有必要了解其核心技术点和相关实现原理,以下将详细介绍文件中提及的关键知识点...

    Java并发编程:深入解析抽象队列同步器(AQS)及其在Lock中的应用

    本文深入探讨了Java并发编程的关键组件——抽象队列同步器(AQS)及其在ReentrantLock的应用。AQS是处理线程同步问题的高效工具,是Java并发编程中的核心。文章首先简要介绍了并发编程领域的先驱Doug Lea。重点在于...

    AQS源码分析 (1).pdf

    AQS全称为AbstractQueuedSynchronizer,是java中用于构建锁以及其他同步器的一个框架。在多线程的编程中,同步问题是一个非常重要的问题,而AQS正是为了解决这个问题而生的。 首先,我们需要了解的是AQS的核心思想...

    图灵Java高级互联网架构师第6期并发编程专题笔记.zip

    04-Java并发线程池底层原理详解与源码分析-monkey 05-并发编程之深入理解Java线程-fox 06-并发编程之CAS&Atomic原子操作详解-fox 07-并发锁机制之深入理解synchronized(一)-fox 08-并发锁机制之深入理解...

    阿里专家级并发编程架构师课程 彻底解决JAVA并发编程疑难杂症 JAVA并发编程高级教程

    课程内容包括了JAVA手写线程池,UC线程池API详解,线程安全根因详解,锁与原子类,分布式锁原理与实现方式,并发编程-AQS等等针对性非常强的JAVA编程开发教程,这其中的内容对JAVA开发技能的拔尖,非常的有帮助。...

    JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS.docx

    ### JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS #### 引言 《JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS》是一篇详细介绍Java实用并发工具包(Java Util Concurrency,简称J.U.C.)中重要...

    多线程与高并发编程笔记、源码等

    标题“多线程与高并发编程笔记、源码等”表明了资源的核心内容,涵盖了多线程和高并发编程的理论与实践。多线程允许一个应用程序同时执行多个任务,而高并发则指系统能够处理大量并发请求的能力。这两个概念在现代...

    阿里专家级并发编程架构师课程-网盘链接提取码下载 .txt

    课程内容包括了JAVA手写线程池,UC线程池API详解,线程安全根因详解,锁与原子类,分布式锁原理与实现方式,并发编程-AQS等等针对性非常强的JAVA编程开发教程,这其中的内容对JAVA开发技能的拔尖,非常的有帮助。...

    Java并发编程原理与实战

    线程的初始化,中断以及其源码讲解.mp4 多种创建线程的方式案例演示(一)带返回值的方式.mp4 多种创建线程的方式案例演示(二)使用线程池.mp4 Spring对并发的支持:Spring的异步任务.mp4 使用jdk8提供的lambda进行...

    java并发编程-AQS和JUC实战

    ### Java并发编程-AQS和JUC实战 #### 一、ReentrantLock 重入锁 **1.1 概述** - **基本介绍**: `ReentrantLock` 是一个实现了 `Lock` 接口的可重入互斥锁,提供比 `synchronized` 更丰富的功能。与 `synchronized...

    龙果 java并发编程原理实战

    第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...

    Java并发之AQS详解.pdf

    Java并发之AQS详解 AbstractQueuedSynchronizer(AQS)是 Java 并发编程中的一个核心组件,提供了一套多线程访问共享资源的同步器框架。AQS 定义了两种资源共享方式:Exclusive(独占)和 Share(共享)。在 AQS 中...

    Java并发 结合源码分析AQS原理

    Java并发结合源码分析AQS原理 Java并发编程中,AQS(AbstractQueuedSynchronizer)是一个核心组件,它提供了一个基于FIFO队列和状态变量的基础框架,用于构建锁和其他同步装置。在这篇文章中,我们将深入探讨AQS的...

    Java 并发编程原理与实战视频

    第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...

    Java并发系列之AbstractQueuedSynchronizer源码分析(条件队列)

    在Java并发编程中,`AbstractQueuedSynchronizer`(AQS)是一个重要的抽象类,用于构建锁和其他同步组件。AQS的核心是通过一个整型变量`state`来表示同步状态,并利用双端队列(FIFO)管理等待的线程。在本篇中,我们...

Global site tag (gtag.js) - Google Analytics