生产者消费者模式(问题)
数据缓存区存放“产品”,如果缓存区没有“产品”,生产者将产品放入缓存,假如有的话,则停止生产等待消费者取走;反之,缓存区没有“产品”,消费者则停止消费并等待;
(生产者和消费者共享同一个资源)
线程通信
基于Object类的方法,都只能在同步方法或同步代码块中使用,否则会抛出IllegalMonitorStateException异常:
wait() 表示线程一直等待,并释放锁,直到其他线程通知;
wait(long timeout) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的线程;
notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度;
解决生产者消费者问题:
管程法:
生产者:负责生产数据的模块(可能是方法,对象,线程,进程)
消费者:负责处理数据的模块
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
// 生产者消费者 --> 利用缓冲区:管程法 // 生产者,消费者,产品,缓冲区 public class TestPine { public static void main(String[] args) { SynContainer container = new SynContainer(); new Producer(container).start(); new Consumer(container).start(); } } // 生产者 class Producer extends Thread{ SynContainer container; public Producer(SynContainer container){ this.container = container; } // 生产 @Override public void run() { for (int i = 0; i < 100; i++) { container.push(new Product(i)); System.out.println("生产者"+i+"个产品"); } } } // 消费者 class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container){ this.container = container; } // 消费 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了第"+container.pop().id+"个产品"); } } } // 产品 class Product{ int id; public Product(int id) { this.id = id; } } // 缓冲区 class SynContainer{ Product[] products = new Product[10]; // 容器大小 int count = 0; // 容器计数器 // 生产者放入产品 public synchronized void push(Product product){ // 如果容器满了,需要等待消费者消费 if(count == products.length){ // 通知消费者消费,生产等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 如果没有满,需要消耗产品 products[count++] = product; // 通知消费者消费 this.notifyAll(); } // 消费者消费产品 public synchronized Product pop(){ // 判断能否消费 if(count==0){ // 等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 如果可以消费 count--; Product product = products[count]; // 消费完,通知生产者生产 this.notifyAll(); return product; } }
管程法:利用一个容器作为缓冲区,可以容纳多个产品;
// 生产者消费者: 信号灯,标志位 public class TestSignal { public static void main(String[] args) { Order order = new Order(); new Cooker(order).start(); new Eater(order).start(); } } // 生产者 厨师 class Cooker extends Thread{ Order order; public Cooker(Order order){ this.order = order; } @Override public void run() { for (int i = 0; i < 20; i++) { if(i%2==0){ this.order.cook("油焖大虾"); }else{ this.order.cook("红烧排骨"); } } } } // 消费者 顾客 class Eater extends Thread{ Order order; public Eater(Order order){ this.order = order; } @Override public void run() { for (int i = 0; i < 20; i++) { order.eat(); } } } // 产品 下单食物 class Order{ // 厨师做饭, 顾客等待 // 顾客吃饭, 厨师等待 String food; // 下单食物 boolean flag = true; // 做饭 public synchronized void cook(String food){ if(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("厨师做"+ food); // 通知顾客吃饭 this.notifyAll(); // 唤醒 this.food = food; this.flag = !this.flag; } // 吃饭 public synchronized void eat(){ if(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("吃"+food); // 通知厨师做饭 this.notifyAll(); this.flag = !this.flag; } }
信号灯法:通过标志位判断,只能共享一个产品