博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)
阅读量:7045 次
发布时间:2019-06-28

本文共 4370 字,大约阅读时间需要 14 分钟。

hot3.png

一、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             @Override16             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             @Override31             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.
cast(items[takeIndex]); items[takeIndex] = null; takeIndex = inc(takeIndex); --count; notFull.signal();//唤醒一个在Condition等待队列中的线程 return x; }

 

转载于:https://my.oschina.net/u/3346994/blog/899195

你可能感兴趣的文章
go学习笔记(05)-基本语法-常量
查看>>
创建spring自定义注解进行自动装配
查看>>
如何使用DotfuscatorPro_4.9对软件进行加密
查看>>
2018/11/30 一个64位操作系统的实现 第三章 loader程序的导入
查看>>
python wsgi PEP333 中文翻译
查看>>
收费udx
查看>>
构造函数+原型的js混合模式
查看>>
[文章笔记] Wanted: Best Practices for Collaborative Translation (2011)
查看>>
SEO优化网页伪静态的生成方式和伪静态的用处
查看>>
Every thing begin with save my time.
查看>>
win10专业版激活方法
查看>>
关于channel的一些坑
查看>>
对于返回void类型的asyc的异步方法,如何修改,能使用await
查看>>
spring源码 — 五、事务
查看>>
linux 命令 — sed
查看>>
highcharts与highstock实例
查看>>
(最短路 弗洛伊德) Til the Cows Come Home -- POJ --2387
查看>>
(匹配)Oil Skimming -- hdu --4185
查看>>
(最小生成树)Agri-Net -- POJ -- 1258
查看>>
程序员为什么不会修电脑?
查看>>