文章插图
总结:
- notify方法很容易引起死锁,除非你根据自己的程序设计,确定不会发生死锁,notifyAll方法则是线程的安全唤醒方法
- 如果程序允许超时唤醒,则可以使用wait(long timeout)方法
- wait(long timeout,int nanou):与 wait(long timeout)相同,不过提供了纳秒级别的更精确的超时控制
package java.util.concurrent.locks;import java.util.concurrent.TimeUnit;import java.util.Date;public interface Condition {//使当前线程在接到信号或被中断之前一直处于等待状态void await() throws InterruptedException;// 使当前线程在接到信号之前一直处于等待状态 。【注意:该方法对中断不敏感】 。void awaitUninterruptibly();// 使当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态 。// 返回值表示剩余时间,如果在nanosTimesout之前唤醒,那么返回值 = nanosTimeout - 消耗时间,如果返回值 <= 0 ,则可以认定它已经超时了long awaitNanos(long nanosTimeout) throws InterruptedException;// 使当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态boolean await(long time, TimeUnit unit) throws InterruptedException;// 使当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态 。如果没有到指定时间就被通知,则返回true,否则表示到了指定时间,返回返回falseboolean awaitUntil(Date deadline) throws InterruptedException;// 唤醒一个等待线程 。该线程从等待方法返回前必须获得与Condition相关的锁 。void signal();// 唤醒所有等待线程 。能够从等待方法返回的线程必须获得与Condition相关的锁void signalAll();}
在此我们通过经典的生产者消费者案例说一下Condition实现线程通信,多几种案例思维更宽阔,多样化理解对技术刺激更大案例:有一个快递点,可以接货和送货,最多存放5个包裹,再放就提示包裹已满,派件时包裹送完就不能再送,提示没有包裹,不能派送
快递点:
package com.stt.thread.communication;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;/** * 快递点: * goodsNumber: 快递数量,默认为0,最多5个,保障原子性使用 AtomicInteger* receiving() : 收货方法,累加货物数量,每次 + 1 * dispatch() : 派送方法,递减数量,每次 - 1 * 注意:因为使用 Condition 实现,Condition 需要通过 ReentrantLock 获取, *所以可以使用 ReentrantLock实现同步就不需要 synchronized */public class ExpressPoint {// 快递数量,使用原子类private AtomicInteger goodsNumber = new AtomicInteger();// 锁对象private ReentrantLock lock = new ReentrantLock();// 创建线程通信对象private Condition condition = lock.newCondition();// 收货方法,使用Lock锁,就不需要synchronized同步了public void receiving() {// 上锁lock.lock();// 写try...finally,保障无论是否发生异常都可以解锁,避免死锁try {// 如果达到5个,就提示,并且等待while (goodsNumber.get() == 5) {System.out.println("库房已满,已不能再接收!");// 等待,有异常抛出condition.await();}System.out.println(Thread.currentThread().getName() + "已收到编号:" + goodsNumber.incrementAndGet() + "的包裹");// 唤醒其他线程condition.signalAll();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {// 解锁lock.unlock();}}// 派送方法public void dispatch() {// 上锁lock.lock();try {// 等于0就不能再派送while (goodsNumber.get() == 0) {System.out.println("没有包裹,不能派送!");condition.await();}System.out.println(Thread.currentThread().getName() + "已送出编号:" + goodsNumber.get() + "的包裹");goodsNumber.decrementAndGet();condition.signalAll();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {// 解锁lock.unlock();}}}
测试类:通过while死循环,不断接货和送货public class ExpressPointMain {public static void main(String[] args) {ExpressPoint expressPoint = new ExpressPoint();// 收货线程new Thread(() -> {while (true){expressPoint.receiving();}},"收货员").start();// 送货线程new Thread(() -> {while (true){expressPoint.dispatch();}},"送货员").start();}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一个水煮鸡蛋白的热量
- 重庆|3条私密视频外泄!景甜你糊涂呀,张柏芝阿娇的血泪教训你不懂吗
- 夏文汐|香港知名女星突然宣布复出,疑与富商丈夫离婚,多次被传和小鲜肉搞暧昧
- 景甜|3条私密视频外泄!景甜你糊涂呀,张柏芝阿娇的血泪教训你不懂吗
- 隐婚|大瓜!已婚男星与85后女闺蜜关系不纯,早先隐婚便于乱搞
- 隐婚|曝翻红男星婚后乱搞,与85花闺蜜乱玩,隐婚多年因方便约会
- 隐婚|大瓜!曝已婚翻红男星与85后女闺蜜关系不纯,早先隐婚便于乱搞
- |处于上升期的职场年轻人,到底该不该搞副业?
- 电影|何莉莉:你们笑我是风月片女王,我笑你们不懂70亿港币是有多重!
- 一个胡萝卜的热量