`
milagro
  • 浏览: 13777 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

转 Java并发编程J.U.C之Condition

阅读更多

在上一篇中,我们了解了下J.U.C的锁的获取与释放的过程 ,这个过程主要通过在A.Q.S中维持一个等待队列来实现,其中我们也提到了,在A.Q.S中除了一个等待队列之外,还有一个Condition队列,在了解Condition队列之前,先来看一下Condition是怎么回事:

 

 写道
The synchronizer framework provides a ConditionObject class for use by synchronizers that maintain exclusive synchronization and conform to the Lock interface. Any number of condition objects may be attached to a lock object, providing classic monitor-style await, signal, and signalAll operations, including those with timeouts, along with some inspection and monitoring methods.

 

上面的这一段内容摘自Doug Lea的AQS论文 ,从上面这一段话可以看出,Condition主要是为了在J.U.C框架中提供和Java传统的监视器风格的wait,notify和notifyAll方法类似的功能,那么先来解释一下这三个方法的作用:

  • Object.wait()方法:使当前线程释放Object上的监视器并且挂起,直到有另外的线程调用Object.notify()方法或者Object.notifyAll()方法唤醒当前线程,当被唤醒后,Object.wait()方法会尝试重新获取监视器,成功获取后继续往下执行。注意Object.wait()方法只有在当前线程持有Object的监视器的时候才能够调用,不然会抛出异常。
  • Object.notify()方法:用于唤醒另外一个调用了Object.wait()方法的线程,如果有多个都调用了Object.wait()方法,那么就会选择一个线程去notify(),具体选择哪一个和具体的实现有关,当前线程在调用Object.notify()方法以后会就释放Object的监视器,和wait()方法一样,Object.notify()方法只有在当前线程只有Object的监视器的时候才能够调用,不然就会抛出异常。
  • Object.notifyAll()方法:唤醒所有调用了Object.wait()方法的线程,如果有多个线程调用了Object.wait()方法,那么就会引发这些线程之间的竞争,最后谁成功获取到Object的监视器和具体的实现有关,当前线程在调用Object.notifyAll()方法以后会就释放Object的监视器,和wait()方法一样,Object.notifyAll()方法只有在当前线程只有Object的监视器的时候才能够调用,不然就会抛出异常。

那么Condition是如何实现wait,notify和notifyAll方法的功能呢?我们接下来看:

在Condition中,wait,notify和notifyAll方法分别对应了await,signal和signalAll方法,当然Condition也提供了超时的、不可被中断的await()方法,不过我们主要还是看一看await,notify和notifyAll的实现,先看await:

await方法:

Java代码  收藏代码
  1. public final void await() throws InterruptedException {  
  2.     if (Thread.interrupted())  
  3.         throw new InterruptedException();  
  4.     Node node = addConditionWaiter();  
  5.     int savedState = fullyRelease(node);  
  6.     int interruptMode = 0;  
  7.     while (!isOnSyncQueue(node)) {  
  8.         LockSupport.park(this);  
  9.         if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)  
  10.             break;  
  11.     }  
  12.     if (acquireQueued(node, savedState) && interruptMode != THROW_IE)  
  13.         interruptMode = REINTERRUPT;  
  14.     if (node.nextWaiter != null)  
  15.         unlinkCancelledWaiters();  
  16.     if (interruptMode != 0)  
  17.         reportInterruptAfterWait(interruptMode);  
  18. }  
 
整个await的过程如下:
  1. 在第2行处,如果当前线程被中断,则抛出中断异常。
  2. 在第4行处,将节点加入到Condition队列中去,这里如果lastWaiter是cancel状态,那么会把它踢出Condition队列。
  3. 在第5行处,调用tryRelease,释放当前线程的锁
  4. 在第7行处,判断节点是否在等待队列中(signal操作会将Node从Condition队列中拿出并且放入到等待队列中去),如果不在等待队列中了,就park当前线程,如果在,就退出循环,这个时候如果被中断,那么就退出循环
  5. 在第12行处,这个时候线程已经被signal()或者signalAll()操作给唤醒了,退出了4中的while循环,尝试再次获取锁,调用acquireQueued方法。

可以看到,这个await的操作过程和Object.wait()方法是一样,只不过await()采用了Condition队列的方式实现了Object.wait()的功能。

signal和signalAll方法:

在了解了await方法的实现以后,signal和signalAll方法的实现就相对简单了,先看看signal方法:

Java代码  收藏代码
  1. public final void signal() {  
  2.     if (!isHeldExclusively())  
  3.         throw new IllegalMonitorStateException();  
  4.     Node first = firstWaiter;  
  5.     if (first != null)  
  6.         doSignal(first);  
  7. }  
 
这里先判断当前线程是否持有锁,如果没有持有,则抛出异常,然后判断整个condition队列是否为空,不为空则调用doSignal方法来唤醒线程,看看doSignal方法都干了一些什么:
Java代码  收藏代码
  1. private void doSignal(Node first) {  
  2.     do {  
  3.         if ( (firstWaiter = first.nextWaiter) == null)  
  4.             lastWaiter = null;  
  5.         first.nextWaiter = null;  
  6.     } while (!transferForSignal(first) &&  
  7.              (first = firstWaiter) != null);  
  8. }  
 
这个while循环的作用就是将firstWaiter往Condition队列的后面移一位,并且唤醒first,看看while循环中tranferForSignal:
Java代码  收藏代码
  1. final boolean transferForSignal(Node node) {  
  2.     /* 
  3.      * If cannot change waitStatus, the node has been cancelled. 
  4.      */  
  5.     if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))  
  6.         return false;  
  7.    
  8.     /* 
  9.      * Splice onto queue and try to set waitStatus of predecessor to 
  10.      * indicate that thread is (probably) waiting. If cancelled or 
  11.      * attempt to set waitStatus fails, wake up to resync (in which 
  12.      * case the waitStatus can be transiently and harmlessly wrong). 
  13.      */  
  14.     Node p = enq(node);  
  15.     int c = p.waitStatus;  
  16.     if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL))  
  17.         LockSupport.unpark(node.thread);  
  18.     return true;  
  19. }  
 

这段代码的作用就是修改Node的waitStatus为0,然后将Node插入到等待队列中,并且唤醒Node。

signalAll和signal方法类似,主要的不同在于它不是调用doSignal方法,而是调用doSignalAll方法:

Java代码  收藏代码
  1. private void doSignalAll(Node first) {  
  2.     lastWaiter = firstWaiter  = null;  
  3.     do {  
  4.         Node next = first.nextWaiter;  
  5.         first.nextWaiter = null;  
  6.         transferForSignal(first);  
  7.         first = next;  
  8.     } while (first != null);  
  9. }  
 
这个方法就相当于把Condition队列中的所有Node全部取出插入到等待队列中去。

总结:

在了解了await(),signal()和signalAll方法的实现以后,我们再来通过一副gif动画来看一看这一个整体的过程:


 

 

分享到:
评论

相关推荐

    JAVA并发编程实战.pdf

    根据提供的文件信息:“JAVA并发编程实战.pdf”,我们可以深入探讨与Java并发编程相关的多个核心知识点。 ### Java并发编程基础 #### 1. 并发与并行 - **并发(Concurrency)**:指一个程序中存在多个执行序列(如...

    java并发编程实战.zip

    《Java并发编程实战》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了Java并发的核心概念、工具和最佳实践,旨在帮助读者在多线程环境中构建高效、可靠的系统。以下是本书涉及的一些关键知识点: 1. *...

    Java并发编程实践.rar

    《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了从基础到高级的并发编程概念,旨在帮助读者提升在多线程环境下的编程能力,优化系统性能,避免并发问题。以下是对该书内容的详细...

    Java并发编程ppt.rar

    Java并发编程是软件开发中的一个核心领域,尤其是在服务器端应用和多核处理器系统中,它的重要性日益凸显。这个“Java并发编程ppt”压缩包文件很可能包含了一套详细的讲解材料,帮助学习者理解并掌握Java环境下的多...

    Java并发编程全景图.pdf

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

    [Java并发编程实践].(Java.Concurrency.in.Practice).Brian.Goetz.文字版(1)

    《Java并发编程实践》是Java并发领域的一本经典著作,由Brian Goetz等多位专家合著。这本书深入探讨了如何在Java环境中有效地进行多线程和并发编程,以充分利用现代多核处理器的性能。以下是对本书核心知识点的详细...

    Java并发编程书籍高清版

    本资源包含三本权威的Java并发编程书籍:《Java并发编程实践》、《java并发编程的艺术》以及Brian Goetz的文字版《Java并发编程实践》。 首先,我们来看《Java并发编程实践》(Java Concurrency in Practice)这...

    ( java并发编程.zip )文字版 电子书 高清版

    《Java并发编程》是一本深度探讨Java平台上的并发与多线程编程的权威书籍,适合对并发编程有深入了解需求的开发者阅读,特别是对于那些志在加入BAT(百度、阿里巴巴、腾讯)等顶级互联网企业的程序员来说,这本书是...

    java并发编程与实践

    "Java并发编程与实践"文档深入剖析了这一主题,旨在帮助开发者理解和掌握如何在Java环境中有效地实现并发。 并发是指在单个执行单元(如CPU)中同时执行两个或更多任务的能力。在Java中,这主要通过线程来实现,...

    《Java 并发编程实战》.zip

    《Java 并发编程实战》是一本专注于Java并发编程领域的权威书籍,旨在帮助开发者深入理解和掌握在多线程环境中编写高效、安全且可维护的代码。这本书涵盖了Java并发编程的基础概念,高级特性以及最佳实践,是Java...

    Java并发编程设计原则和模式

    本资料“Java并发编程设计原则和模式”深入探讨了如何在Java环境中有效地进行并发处理,以充分利用系统资源并避免潜在的并发问题。 一、并发编程基础 并发是指两个或多个操作在同一时间段内执行,但并不意味着这些...

    Java并发编程基础.pdf

    ### Java并发编程基础知识点 #### 一、线程与线程状态 - **线程基本概念**: - 在Java中,线程是程序执行流的最小单元,它由一个线程体(实现Runnable接口或者继承Thread类)和数据组成。 - **线程创建**:可以...

    Java 并发核心编程

    ### Java 并发核心编程知识点解析 #### 一、Java并发概述 自Java诞生之初,其设计者就赋予了该语言强大的并发处理能力。Java语言内置了对线程和锁的支持,这...理解和掌握这些概念和技术是成功进行并发编程的关键。

    Java并发编程学习笔记.

    Java并发编程是Java开发中的重要领域,它涉及到多线程、同步、锁机制、线程池等关键概念,是提高程序性能和效率的关键技术。在Java中,并发编程的运用可以充分利用多核处理器的能力,实现高效的多任务处理。以下是对...

    Java并发编程学习笔记

    Java并发编程是指在Java语言中编写多线程和多任务执行的程序,以便更高效地利用计算机的多核处理器资源。并发编程是Java高级编程技能中的重要组成部分,尤其是在需要处理大量数据、提供快速响应、实现高吞吐量和高可...

    Java并发编程实践源码

    《Java并发编程实践》是一本深入探讨Java多线程与并发编程的经典著作,其源码提供了丰富的示例,帮助读者理解和应用并发编程的核心概念。在这些文件中,我们可以看到多种并发设计模式和策略的实际运用,下面将逐一...

    Java 并发编程实战-随书源码

    《Java并发编程实战》这本书是Java开发者深入理解并发编程的重要参考书籍。本书旨在帮助程序员解决在多线程环境中遇到的实际问题,提升系统性能并保证其稳定性。随书源码提供了丰富的示例,让读者能够动手实践,加深...

    一本经典的多线程书籍 Java并发编程 设计原则与模式 第二版 (英文原版)

    《Java并发编程 设计原则与模式 第二版》是一本深受程序员喜爱的经典书籍,由Addison Wesley出版。这本书深入探讨了Java平台上的多线程编程技术,为开发者提供了丰富的设计原则和模式,帮助他们理解和解决并发环境中...

    JAVA并发编程实践 EN(全)

    1. **并发基础**:介绍Java并发编程的基本概念,包括线程、进程、同步与互斥、死锁等。读者将了解Java中Thread类和Runnable接口的使用,以及如何创建和管理线程。 2. **线程安全**:讨论线程不安全的代码示例,以及...

    Java并发编程原理与实战

    Spring对并发的支持:Spring的异步任务.mp4 使用jdk8提供的lambda进行并行计算.mp4 了解多线程所带来的安全风险.mp4 从线程的优先级看饥饿问题.mp4 从Java字节码的角度看线程安全性问题.mp4 synchronized保证线程...

Global site tag (gtag.js) - Google Analytics