【多线程】java多线程实现生产者消费者模式 synchronized+Object的wait/notify方式 和 Lock+Condition的await/signal方式
=========================使用synchronized,配合Object的wait()/notify()实现生产者消费者======================
思考问题:
1.为什么用wait()+notify()实现生产者消费者模式?
wait()方法可以暂停线程,并释放对象锁
notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了synchronized临界区后,才会把锁释放
2.为什么wait()、notify()、notifyAll()方法需要放在同步代码块中执行?
wait()方法暂停线程执行,并立即释放对象锁 notify()/notifyAll() 方法唤醒其他等待该对象锁的线程,并在执行完同步代码块中的后续步骤后,释放对象锁 notify()和notifyAll()的区别在于: notify只会唤醒其中一个线程, notifyAll则会唤醒全部线程。 至于notify会唤醒哪个线程,是由线程调度器决定的。
因为这三个方法都需要获取到对象锁才能有效执行。否则就会抛异常:java.lang.IllegalMonitorStateException
3.wait()是暂停的哪个线程?notify()唤醒的是哪个线程?
wait()是暂停当前线程。
notify()则是唤醒等待当前对象锁的线程
4.什么是生产者消费者模式
一个产数据,一个用数据,中间最多再加上个存取仓库
生产者消费者模式 就是java多线程通信一个很好的例子
5.生产着消费者模式特点是什么
1.解耦,生产者干生产者的事情,消费者干消费者的事情
2.支持高并发,可以同时多个生成,多个消费,互不影响
6.一对一的生产者消费者模式:
1>早餐类:
package com.sxd.swapping.test.ProducerAndConsumerTest; /** * 早餐基础类 * * wait() * notify() * notifyAll() * 三个方法 需要放在同步代码块中执行 因为要获取对象锁 */ public class Breakfast{ private String food; private String drink; private boolean flag = false;//flag = false 表示需要生产 flag = true 表示需要消费 public synchronized void makeBreakfast(String food,String drink){ System.out.println("生产者进入--->标志值为:"+flag); if (flag){ try { System.out.println("make---wait()暂停,释放对象锁"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.food = food; try { System.out.println("make---sleep()休眠,不释放对象锁"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.drink = drink; System.out.println("make---生产者制造东西完成----"); this.flag = true; System.out.println("make---notify()唤醒,标志值为"+flag); notify(); } public synchronized void eatBreakfast(){ System.out.println("消费者进入--->标志值为:"+flag); if(!flag){ try { System.out.println("eat---wait()"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { System.out.println("eat---sleep()"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("吃东西---"+this.food+";喝东西---"+this.drink); this.flag = false; System.out.println("eat---notify()唤醒,标志值为"+flag); notify(); } }
2> 生产者类:
package com.sxd.swapping.test.ProducerAndConsumerTest; public class Producer implements Runnable{ private Breakfast breakfast; public Producer(Breakfast breakfast) { this.breakfast = breakfast; } @Override public void run() { int i = 7; for (int i1 = 0; i1 < i; i1++) { if (i1 %2 == 0){ this.breakfast.makeBreakfast("馒头","豆浆"); }else { this.breakfast.makeBreakfast("面包","冷饮"); } } } }
3>消费者类:
package com.sxd.swapping.test.ProducerAndConsumerTest; public class Consumer implements Runnable{ private Breakfast breakfast; public Consumer(Breakfast breakfast) { this.breakfast = breakfast; } @Override public void run() { int i = 7; for (int i1 = 0; i1 < i; i1++) { System.out.println("星期"+(i1+1)+"---消费者要来吃东西了"); this.breakfast.eatBreakfast(); } } }
4>线程启动主测试类:
package com.sxd.swapping.test.ProducerAndConsumerTest; public class Test { public static void main(String[] args) { Breakfast breakfast = new Breakfast(); new Thread(new Producer(breakfast)).start(); new Thread(new Consumer(breakfast)).start(); } }
5>展示结果:
===========================使用Lock,配合Condition的await()/signal()实现生产者消费者============================
1.早饭类,提供生产方法和消费方法
package com.sxd.swapping.test.ProducerAndConsumerTest; import java.util.LinkedList; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * * Lock配合condition实现生产者消费者模式 * * @author sxd * @date 2019/8/6 9:08 */ public class Condition_Breakfast { private LinkedList<String> breakfastList;//早饭资源容器 private int maxSize;//最大量早饭资源数量 自定义 private Lock lock; //锁 private Condition comsumerCondition;//满条件【即代表消费者等待队列】 private Condition producerCondition;//不满条件【即代表生产者等待队列】 //自定义 最大共享资源数量 public Condition_Breakfast(int maxSize) { this.maxSize = maxSize; breakfastList = new LinkedList<>(); lock = new ReentrantLock(); comsumerCondition = lock.newCondition(); producerCondition = lock.newCondition(); } public void produce(String str){ lock.lock(); try { while (maxSize == breakfastList.size()){ System.out.println("如果早餐共享资源已经满足最大量,则进入本方法的当前线程们,进入notFullCondition的等待队列中,线程挂起"); producerCondition.await(); } breakfastList.add(str); System.out.println("生产早饭:"+str); System.out.println("早饭已经被生产了,唤醒消费者等待队列中的线程,可以继续开始消费了"); comsumerCondition.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public String consume(){ String str = null; lock.lock(); try { while (breakfastList.size() == 0 ){ System.out.println("如果早饭共享资源完全==0,就将消费者们挂起,等待生产者生产后再去唤醒消费者们"); comsumerCondition.await(); } str = breakfastList.poll(); System.out.println("消费早饭:"+str); System.out.println("早饭已经被消费了,唤醒生产者等待队列中的 线程,可以继续生产了"); producerCondition.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } return str; } }
2.早饭类的生产者
package com.sxd.swapping.test.ProducerAndConsumerTest; /** * @author sxd * @date 2019/8/6 9:26 */ public class Condition_Producer implements Runnable { Condition_Breakfast breakfast; public Condition_Producer(Condition_Breakfast breakfast) { this.breakfast = breakfast; } @Override public void run() { int i = 7; String threadName = Thread.currentThread().getName(); for (int i1 = 0; i1 < i; i1++) { if (i1 %2 == 0){ this.breakfast.produce(threadName+"大馒头"+i1); }else { this.breakfast.produce(threadName+"大包子"+i1); } } } }
3.早饭类的消费者
package com.sxd.swapping.test.ProducerAndConsumerTest; /** * @author sxd * @date 2019/8/6 9:28 */ public class Condition_Comsumer implements Runnable{ Condition_Breakfast breakfast; public Condition_Comsumer(Condition_Breakfast breakfast) { this.breakfast = breakfast; } @Override public void run() { int i = 7; for (int i1 = 0; i1 < i; i1++) { this.breakfast.consume(); } } }
4.测试类
package com.sxd.swapping.test.ProducerAndConsumerTest; /** * @author sxd * @date 2019/8/6 9:30 */ public class Test2 { public static void main(String[] args) { Condition_Breakfast breakfast = new Condition_Breakfast(16); new Thread(new Condition_Producer(breakfast)).start(); new Thread(new Condition_Producer(breakfast)).start(); new Thread(new Condition_Producer(breakfast)).start(); new Thread(new Condition_Comsumer(breakfast)).start(); new Thread(new Condition_Comsumer(breakfast)).start(); new Thread(new Condition_Comsumer(breakfast)).start(); } }
5.启动效果