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】