java多线程(7)---Condition
Condition
一、Condition概述
在线程的同步时可以使一个线程阻塞而等待一个信号,同时放弃锁使其他线程可以能竞争到锁。
在synchronized中我们可以使用Object的wait()和notify方法实现这种等待和唤醒。
在Lock可以实现相同的功能就是通过Condition。Condition中的await()和signal()/signalAll()就相当于Object的wait()和notify()/notifyAll()。
除此之外,Condition还是对多线程条件进行更精确的控制。notify()是唤醒一个线程,但它无法确认是唤醒哪一个线程。 但是,通过Condition,就能明确的指定唤醒读线程。
二、Condition和Object案例对比
案例说明:生成者在仓库满时,进入等待状态,同时唤醒消费者线程,消费者在仓库为空时,进入等待。同时唤醒生产者线程。
1、采用await()和signal()方式
(1)测试类
public class ConditionLockTest { public static void main(String[] args){ //相当于仓库 Depot depot=new Depot(); //创建两个生产者一个消费者 Producer producer1=new Producer(depot); Producer producer2=new Producer(depot); Consumer consumer1=new Consumer(depot); //采用线程池方式 Executor executors=Executors.newFixedThreadPool(5); executors.execute(producer1); executors.execute(producer2); executors.execute(consumer1); } } //生产者 class Producer implements Runnable { Depot depot; public Producer(Depot depot){ this.depot=depot; } public void run(){ while(true){ depot.prod(); } } } //消费者 class Consumer implements Runnable{ Depot depot; public Consumer(Depot depot){ this.depot=depot; } public void run(){ while(true){ depot.consum(); } } }
(2)仓库类
public class Depot { //初始仓库为0,最大为10,超过10生产者停止生产 private int size; private int maxSize=10; private Condition prodCondition; private Condition consumCondition; private Lock lock; public Depot(){ this.size=0; this.lock=new ReentrantLock(); //可以看出Condition对象依赖于Lock锁 this.prodCondition=this.lock.newCondition(); this.consumCondition=this.lock.newCondition(); } /* * 生产者生产方法 */ public void prod(){ lock.lock(); try{ //如果生产超过max值,则生产者进入等待 while(size+1>maxSize){ try { System.out.println(Thread.currentThread().getName()+"生产者进入等待状态"); prodCondition.await(); } catch (Exception e) { e.printStackTrace(); } } size+=1; System.out.println(Thread.currentThread().getName()+" 生产了一个 "+1+" 总共还有 "+size); //唤醒消费者线程 consumCondition.signal(); }finally { lock.unlock(); } } /* * 消费者消费方法 */ public void consum(){ lock.lock(); try{ //如果当前大小减去要消费的值,如果小于0的话,则进入等待 while(size-1<0){ try { System.out.println(Thread.currentThread().getName()+" 消费者进入等待状态"); consumCondition.await(); } catch (Exception e) { e.printStackTrace(); } } size-=1; System.out.println(Thread.currentThread().getName()+" 消费者消费了 "+1+" 个,总共还有 "+size); //唤醒生产者线程 prodCondition.signal(); }finally { lock.unlock(); } } }
运行结果(截取部分图)
根据结果分析可以得出:
生产者生产产品,当超过10个,生产者会处于等待状态,直到消费者消费者消费了一个产品,生产者才会重新唤醒。
2、采用wait()和notifyAll()方法
(1)仓库类代码(测试类代码不变)
public class Depot { //初始仓库为0,最大为10,超过10生产者停止生产 private int size; private int maxSize=10; public Depot(){ this.size=0; } /* * 生产者生产方法 */ public synchronized void prod(){ try{ //如果生产超过max值,则生产者进入等待 while(size+1>maxSize){ try { //采用wait方法 wait(); System.out.println(Thread.currentThread().getName()+"生产者进入等待状态"); } catch (Exception e) { e.printStackTrace(); } } size+=1; System.out.println(Thread.currentThread().getName()+" 生产了一个 "+1+" 总共还有 "+size); //唤醒所有线程 notifyAll(); }finally { } } /* * 消费者消费方法 */ public synchronized void consum(){ try{ //如果当前大小减去要消费的值,如果小于0的话,则进入等待 while(size-1<0){ try { wait(); System.out.println(Thread.currentThread().getName()+" 消费者进入等待状态"); } catch (Exception e) { e.printStackTrace(); } } size-=1; System.out.println(Thread.currentThread().getName()+" 消费者消费了 "+1+" 个,总共还有 "+size); //唤醒所有线程 notifyAll(); }finally { } } }
运行结果:
对比:
首先可以看出两个都可以实现生产者消费者的工作,不过可以发现Condition的signal相对于Object的notify最大有点就是它可以唤醒指定的线程,
比如这里可以指定唤醒生产线程或者消费线程,而用notify是不能唤醒指定线程的,你只能通过notifyAll来唤醒所有。
想太多,做太少,中间的落差就是烦恼。想没有烦恼,要么别想,要么多做。少校【14】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了