Java多线程编程笔记之Condition

本篇内容基于JDK7,涉及Condition常用方法。

1.概述 Condition接口位于java.util.concurrent.locks包下,实现类有 AbstractQueuedLongSynchronizer.ConditionObject和 AbstractQueuedSynchronizer.ConditionObject。Condition将Object监视器方法(wait、notify和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用。其中,Lock替代了synchronized方法的使用及作用,Condition替代了Object监视器方法的使用及作用。Condition的await方法代替Object的wait;Condition的signal方法代替Object的notify方法;Condition的signalAll方法代替Object的notifyAll方法。Condition实例在使用时需要绑定到一个锁上,可以通过newCondition方法获取Condition实例。Condition实现可以提供不同于Object监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁。

2.使用样例 下面的代码演示了Condition简单使用的样例。

public class ConditionDemo {
    @Test    
    public void test() {
        final ReentrantLock reentrantLock = new ReentrantLock();
        final Condition condition = reentrantLock.newCondition();        
        new Thread(new Runnable() {
            @Override            
            public void run() {                
                try {
                    reentrantLock.lock();
                    System.out.println(Thread.currentThread().getName() + "在等待被唤醒");
                    condition.await();
                    System.out.println(Thread.currentThread().getName() + "恢复执行了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        }, "thread1").start();        
        new Thread(new Runnable() {
            @Override            
            public void run() {                
                try {
                    reentrantLock.lock();
                    System.out.println(Thread.currentThread().getName() + "抢到了锁");
                    condition.signal();
                    System.out.println(Thread.currentThread().getName() + "唤醒其它等待的线程");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        }, "thread2").start();
    }
}

输出结果如下所示:

thread1在等待被唤醒
thread2抢到了锁
thread2唤醒其它等待的线程
thread1恢复执行了

3.创建Condition实例 通过Lock接口实现类的newCondition方法获取Condition实例,例如如下代码:

ReentrantLock reentrantLock = new ReentrantLock();
Condition condition = reentrantLock.newCondition();

4.常用方法 4.1 await() 调用await方法后,当前线程在接收到唤醒信号之前或被中断之前一直处于等待休眠状态。调用此方法时,当前线程保持了与此Condition有关联的锁,调用此方法后,当前线程释放持有的锁。此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁,在线程返回时,可以保证它保持此锁。

4.2 await(long time,TimeUnit unit) 调用此方法后,会造成当前线程在接收到唤醒信号之前、被中断之前或到达指定等待时间之前一直处于等待状态。调用此方法时,当前线程保持了与此Condition有关联的锁,调用此方法后,当前线程释放持有的锁。time参数为最长等待时间;unit参数为time的时间单位。如果在从此方法返回前检测到等待时间超时,则返回 false,否则返回true。此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁,在线程返回时,可以保证它保持此锁。

4.3 awaitNanos(long nanosTimeout) 该方法等效于await(long time,TimeUnit unit)方法,只是等待的时间是 nanosTimeout指定的以毫微秒数为单位的等待时间。该方法返回值是所剩毫微秒数的一个估计值,如果超时,则返回一个小于等于0的值。可以根据该返回值来确定是否要再次等待,以及再次等待的时间。

4.4 awaitUninterruptibly() 调用此方法后,会造成当前线程在接收到唤醒信号之前一直处于等待状态。如果在进入此方法时设置了当前线程的中断状态,或者在等待时,线程被中断,那么在接收到唤醒信号之前,它将继续等待。当最终从此方法返回时,仍然将设置其中断状态。调用此方法时,当前线程保持了与此Condition有关联的锁,调用此方法后,当前线程释放持有的锁。此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁,在线程返回时,可以保证它保持此锁。

4.5 awaitUntil(Date deadline) 调用此方法后,会造成当前线程在接收到唤醒信号之前、被中断之前或到达指定最后期限之前一直处于等待休眠状态。调用此方法时,当前线程保持了与此Condition有关联的锁,调用此方法后,当前线程释放持有的锁。此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁,在线程返回时,可以保证它保持此锁。

4.6 signal() 唤醒一个等待线程,如果所有的线程都在等待此条件,则选择其中的一个唤醒。在从await返回之前,该线程必须重新获取锁。

4.7 signalAll() 唤醒所有等待线程,如果所有的线程都在等待此条件,则唤醒所有线程。 在从await返回之前,每个线程必须重新获取锁。

原文发布于微信公众号 - JavaQ(Java-Q)

原文发表时间:2016-08-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户2442861的专栏

java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?

在Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity。所有对象的非同步方法都能够在...

31410
来自专栏Java成长之路

深入理解多线程

多线程是java中比较重要的一部分内容,使用多线程有许多的优点: - 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。 - 程序需要实现一些需...

25330
来自专栏noteless

javaweb请求编码 url编码 响应编码 乱码问题 post编码 get请求编码 中文乱码问题 GET POST参数乱码问题 url乱码问题 get post请求乱码 字符编码

然后使用      65------>$ 另外一种解码方式解读,显然A就变成了$,这不就是乱码了么

22930
来自专栏python3

python if else 流程判断

Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。 可以通过下图来简单了解条件语句的执行过程:

23620
来自专栏决胜机器学习

PHP面向对象核心(三)——反射、异常处理

PHP面向对象核心(三) (原创内容,转载请注明来源,谢谢) 五、反射 1、反射即PHP运行过程中,提取出关于类、方法、属性、参数等信息,包括 注释信息。动态获...

367120
来自专栏向治洪

命令模式

命令模式定义 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。 作用 命令模式主要应用于将行...

20390
来自专栏从零开始学自动化测试

pytest文档2-用例运行规则

1.查看pytest命令行参数,可以用pytest -h 或pytest —help查看

25930
来自专栏博客园

Asp.Net Web API(三)

    在Asp.Net Web API中,一个控制器就是一个处理HTTP请求的类,控制器的public方法就被叫做action方法或简单的Action。当We...

19250
来自专栏程序员互动联盟

【编程基础】你是否真的了解main()函数?

最近看到很多人、甚至市面上的一些书籍,都使用了void main() ,其实这是错误的。C/C++中从来没有定义过void main() 。C++之父 Bjar...

34060
来自专栏Java编程技术

Dubbo剖析-增强SPI的实现

在Duboo剖析-整体架构分析中介绍了dubbo中除了Service 和 Config 层为 API外,其他各层均为SPI,为SPI意味着下面各层都是组件化可以...

15210

扫码关注云+社区

领取腾讯云代金券