文档章节

java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)

刺猬一号
 刺猬一号
发布于 2017/05/14 13:12
字数 1222
阅读 7
收藏 0
一、Condition 类
  在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的
 java.util.concurrent.locks.ReentrantLock 锁,JDK也为我们提供了与此功能相应的类java.util.concurrent.locks.Condition。Condition与重入锁是通过lock.newCondition()方法产生一个与当前重入锁绑定的
Condtion实例,我们通知该实例来控制线程的等待与通知。该接口的所有方法:

复制代码
public interface Condition {
     //使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。
    void await() throws InterruptedException;

    //调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
    //调用该方法后,结束等待的唯一方法是其它线程调用该条件对象的signal()或signalALL()方法。等待过程中如果当前线程被
中断,该方法仍然会继续等待,同时保留该线程的中断状态。 
    void awaitUninterruptibly();

    // 调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
    //nanosTimeout指定该方法等待信号的的最大时间(单位为纳秒)。若指定时间内收到signal()或signalALL()则返回nanosTimeout减去已经等待的时间;
    //若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,
则返回0或负数。 
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    //与await()基本一致,唯一不同点在于,指定时间之内没有收到signal()或signalALL()信号或者线程中断时该方法会返回
false;其它情况返回true。
    boolean await(long time, TimeUnit unit) throws InterruptedException;

   //适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的
某一时刻。
    boolean awaitUntil(Date deadline) throws InterruptedException;
    
    //唤醒一个在 await()等待队列中的线程。与Object.notify()相似
    void signal();

   //唤醒 await()等待队列中所有的线程。与object.notifyAll()相似
    void signalAll();
}
复制代码
二、使用
1、await()  等待  与 singnal()通知

复制代码
 1 package com.jalja.org.base.Thread;
 2 
 3 import java.util.concurrent.TimeUnit;
 4 import java.util.concurrent.locks.Condition;
 5 import java.util.concurrent.locks.ReentrantLock;
 6 
 7 /**
 8  * Condition 配合Lock  实现线程的等待 与通知
 9  */
10 public class ConditionTest{
11     public static ReentrantLock lock=new ReentrantLock();
12     public static Condition condition =lock.newCondition();
13     public static void main(String[] args) {
14         new Thread(){
15             @Override
16             public void run() {
17                 lock.lock();//请求锁
18                 try{
19                     System.out.println(Thread.currentThread().getName()+"==》进入等待");
20                     condition.await();//设置当前线程进入等待
21                 }catch (InterruptedException e) {
22                     e.printStackTrace();
23                 }finally{
24                     lock.unlock();//释放锁
25                 }
26                 System.out.println(Thread.currentThread().getName()+"==》继续执行");
27             }    
28         }.start();
29         new Thread(){
30             @Override
31             public void run() {
32                 lock.lock();//请求锁
33                 try{
34                     System.out.println(Thread.currentThread().getName()+"=》进入");
35                     Thread.sleep(2000);//休息2秒
36                     condition.signal();//随机唤醒等待队列中的一个线程
37                     System.out.println(Thread.currentThread().getName()+"休息结束");
38                 }catch (InterruptedException e) {
39                     e.printStackTrace();
40                 }finally{
41                     lock.unlock();//释放锁
42                 }
43             }    
44         }.start();
45     }
46 }
复制代码
 

执行结果:

Thread-0==》进入等待
Thread-1=》进入
Thread-1休息结束
Thread-0==》继续执行
流程:在调用await()方法前线程必须获得重入锁(第17行代码),调用await()方法后线程会释放当前占用的锁。同理在调用
signal()方法时当前线程也必须获得相应重入锁(代码32行),调用signal()方法后系统会从condition.await()等待队列中唤醒一
个线程。当线程被唤醒后,它就会尝试重新获得与之绑定的重入锁,一旦获取成功将继续执行。所以调用signal()方法后一定要释放当
前占用的锁(代码41行),这样被唤醒的线程才能有获得锁的机会,才能继续执行。

三、JDK中对Condition 的使用
  我们来看看java.util.concurrent.ArrayBlockingQueue;

  基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞
队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。

  看看他的put方法:

复制代码
  public void put(E e) throws InterruptedException {
        checkNotNull(e);//对传入元素的null判断
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();//对put()方法做同步
        try {
            while (count == items.length)//如果队列已满
                notFull.await();//让当前添加元素的线程进入等待状态
            insert(e);// 如果有其他线程调用signal() 通知该线程 ,则进行添加行为
        } finally {
            lock.unlock();//释放锁
        }
    }
    
    private E extract() {
        final Object[] items = this.items;
        E x = this.<E>cast(items[takeIndex]);
        items[takeIndex] = null;
        takeIndex = inc(takeIndex);
        --count;
        notFull.signal();//唤醒一个在Condition等待队列中的线程
        return x;
    }

 

© 著作权归作者所有

刺猬一号
粉丝 12
博文 373
码字总数 616361
作品 0
深圳
私信 提问
读书笔记之《Java并发编程的艺术》-java中的锁

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
390
0
Java多线程8 条件对象Condition

Java多线程目录 1 简介 Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法...

香沙小熊
2018/12/03
0
0
JUC锁框架——Condition

Condition介绍 Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalA...

长头发-dawn
2018/09/12
11
0
基于AQS的Condition接口

简介 Condition接口实现的功能与Object类中的wait/notify(等待/通知机制)类似,Object的wait和notify/notify是与对象监视器(java线程状态操作和锁与监视器)配合完成线程间的等待/通知机制...

kdy1994
05/21
5
0
死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等...

彤哥读源码
06/03
608
1

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 我,小小编辑,食人族酋长

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @宇辰OSC :分享娃娃的单曲《飘洋过海来看你》: #今日歌曲推荐# 《飘洋过海来看你》- 娃娃 手机党少年们想听歌,请使劲儿戳(这里) @宇辰OSC...

小小编辑
今天
525
10
MongoDB系列-- SpringBoot 中对 MongoDB 的 基本操作

SpringBoot 中对 MongoDB 的 基本操作 Database 库的创建 首先 在MongoDB 操作客户端 Robo 3T 中 创建数据库: 增加用户User: 创建 Collections 集合(类似mysql 中的 表): 后面我们大部分都...

TcWong
今天
28
0
spring cloud

一、从面试题入手 1.1、什么事微服务 1.2、微服务之间如何独立通讯的 1.3、springCloud和Dubbo有哪些区别 1.通信机制:DUbbo基于RPC远程过程调用;微服务cloud基于http restFUL API 1.4、spr...

榴莲黑芝麻糊
今天
15
0
Executor线程池原理与源码解读

线程池为线程生命周期的开销和资源不足问题提供了解决方 案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。 线程实现方式 Thread、Runnable、Callable //实现Runnable接口的...

小强的进阶之路
昨天
40
0
maven 环境隔离

解决问题 即 在 resource 文件夹下面 ,新增对应的资源配置文件夹,对应 开发,测试,生产的不同的配置内容 <resources> <resource> <directory>src/main/resources.${deplo......

之渊
昨天
50
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部