解决了第一个多线程安全的问题,但会出现死锁问题。这很容易分析,将生产方看作一个整体,将消费方也看作一个整体,当生产方线程都wait了(生产方的线程被连续唤醒时会出现该方线程全部wait),消费方也都wait了,死锁就出现了。其实放大了看,将生产方、消费方分别看作一个线程,这两个线程组成多线程,当某一方wait后无法唤醒另一方,另一方也一定会wait,于是就死锁了。
对于双方死锁的问题,只要保证能唤醒对方,而非本方连续唤醒就能解决。使用notifyAll()或signalAll()即可,也可以通过signal()唤醒对方线程解决,见下面的第二段代码。
根据上面的分析,将单生产、单消费模式的代码改进一下,就可以变为多生产多消费单面包模式。、
//代码段1 class Bread { public String name; public int count = 1; public boolean flag = false; } //描述生产者 class Producer implements Runnable { private Bread b; Producer(Bread b){ this.b = b; } public void produce(String name){ b.name = name + b.count; b.count++; } public void run(){ while(true){ synchronized(Bread.class){ while(b.flag){ try{Bread.class.wait();}catch(InterruptedException i){} } produce("面包"); System.out.println(Thread.currentThread().getName()+"----生产者------"+b.name); try{Thread.sleep(10);}catch(InterruptedException i){} b.flag = true; Bread.class.notifyAll(); } } } } //描述消费者 class Consumer implements Runnable { private Bread b; Consumer(Bread b){ this.b = b; } public String consume(){ return b.name; } public void run(){ while(true){ synchronized(Bread.class){ while(!b.flag){ try{Bread.class.wait();}catch(InterruptedException i){} } System.out.println(Thread.currentThread().getName()+"----消费者-------------"+consume()); try{Thread.sleep(10);}catch(InterruptedException i){} b.flag = false; Bread.class.notifyAll(); } } } } public class ProduceConsume_5 { public static void main(String[] args) { //1.创建资源对象 Bread b = new Bread(); //2.创建生产者和消费者对象 Producer pro = new Producer(b); Consumer con = new Consumer(b); //3.创建线程对象 Thread pro_t1 = new Thread(pro); //生产线程1 Thread pro_t2 = new Thread(pro); //生产线程2 Thread con_t1 = new Thread(con); //消费线程1 Thread con_t2 = new Thread(con); //消费线程2 pro_t1.start(); pro_t2.start(); con_t1.start(); con_t2.start(); } }以下是采用Lock和Conditon重构后的代码,使用的是signal()唤醒对方线程的方法。
//代码段2 import java.util.concurrent.locks.*; class Bread { public String name; public int count = 1; public boolean flag = false; public static Lock lock = new ReentrantLock(); public static Condition pro_con = lock.newCondition(); public static Condition con_con = lock.newCondition(); } //描述生产者 class Producer implements Runnable { private Bread b; Producer(Bread b){ this.b = b; } public void produce(String name){ b.name = name + b.count; b.count++; } public void run(){ while(true){ Bread.lock.lock(); try{ while(b.flag){ try{Bread.pro_con.await();}catch(InterruptedException i){} } produce("面包"); System.out.println(Thread.currentThread().getName()+"----生产者------"+b.name); try{Thread.sleep(10);}catch(InterruptedException i){} b.flag = true; Bread.con_con.signal(); //唤醒的是consumer线程 } finally { Bread.lock.unlock(); } } } } //描述消费者 class Consumer implements Runnable { private Bread b; Consumer(Bread b){ this.b = b; } public String consume(){ return b.name; } public void run(){ while(true){ Bread.lock.lock(); try{ while(!b.flag){ try{Bread.con_con.await();}catch(InterruptedException i){} } System.out.println(Thread.currentThread().getName()+"----消费者-------------"+consume()); try{Thread.sleep(10);}catch(InterruptedException i){} b.flag = false; Bread.pro_con.signal(); //唤醒的是producer线程 } finally { Bread.lock.unlock(); } } } } public class ProduceConsume_6 { public static void main(String[] args) { //1.创建资源对象 Bread b = new Bread(); //2.创建生产者和消费者对象 Producer pro = new Producer(b); Consumer con = new Consumer(b); //3.创建线程对象 Thread pro_t1 = new Thread(pro); Thread pro_t2 = new Thread(pro); Thread con_t1 = new Thread(con); Thread con_t2 = new Thread(con); pro_t1.start(); pro_t2.start(); con_t1.start(); con_t2.start(); } }关于多生产、多消费问题做个总结:
(1).解决某一方多线程不同步的方案是使用while(flag)来判断是否wait;
(2).解决双方死锁问题的方案是唤醒对方,可以使用notifyAll(),signalAll()或对方监视器的signal()方法。
6.多生产多消费模式