生产者消费者模式概念:
生产者消费者模式是一个十分经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻。所谓生产者消费者的问题。实际上主要是包含了两类线程
1)一类是生产者线程用于生产数据
2)一类是消费者用于消费数据
为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库
生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;消费者只需要从共享数据区中去获取数据,并不需要关心生产者的行为
生产者消费者模式概述:
为了体现生产和消费过程中的等待和唤醒,java就提供了几个方法供我们使用,这几个方法在object类中object类的等待和唤醒方法:
void wait() 导致当前线程等待,直到另一个线程调用该对象的notify()方法或者 notifyAll()方法
notify() 唤醒正在等待对象监视器的单个线程
notifyAll() 唤醒正在等待对象监视器的所有线程**
例子:生产者-厨师 消费者-客人,定义桌子类存放牛排
厨师煎牛排,桌子上一块都没有 客人需要等待
桌子上牛排满了,厨师不需要生产 需要客人去拿
厨师在煎牛排过程中,如果没有煎完,客人不能去拿
客人没有拿完,不能把客人赶走
生产者消费者代码例子:
public class Table {
LinkedList<Object> list = new LinkedList<>();
private static final int Max=100;
//存储产品
public synchronized void store(String product){
//如果仓库已满 生产者等待;
while (list.size()>Max){
try {
this.wait(); //wait();notify()这两个在同步代码块中,由锁对象调用
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"++存储了"+product);//把产品存进去
list.offer(product);
}
//取产品
public synchronized void take(){
//判断仓库是否为空,当仓库空时需要等待
while (list.size() <= 0){
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
Object product = list.poll();//把前面的产品取出来
System.out.println(Thread.currentThread().getName()+"--消费了"+product);
//通知生产者继续生产
this.notify();
}
}
定义生产者
public class Product extends Thread {
private Table table;
public Product(Table table) {
super();
this.table = table;
}
@Override
public void run(){
for(int i=0;i<30;i++){
String product = "产品编号:"+new Random().nextInt(100);
table.store(product);
}
}
}
定义消费者
public class ConsumerThread extends Thread {
private Table table;
public ConsumerThread(Table table) {
super();
this.table = table;
}
@Override
public void run(){
for(int i=0;i<30;i++){
table.take();
}
}
}
测试类:
class test{
public static void main(String[] args) {
//创建桌子
Table table = new Table();
//创建3个生产者线程模拟三个人
Product p1= new Product(table);
Product p2= new Product(table);
Product p3= new Product(table);
p1.setName("张三");
p2.setName("李四");
p3.setName("王五");
p1.start();
p2.start();
p3.start();
ConsumerThread c1 = new ConsumerThread(table);
ConsumerThread c2 = new ConsumerThread(table);
ConsumerThread c3 = new ConsumerThread(table);
c1.setName("吃货1号");
c2.setName("吃货2号");
c3.setName("吃货3号");
c1.start();
c2.start();
c3.start();
}
}
例子2:两个线程交替打印奇数和偶数
public class PrintNum {
private int num=0;
//打印奇数
public synchronized void printJi(){
//当num是偶数时需要等待
while (num % 2==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":"+num);
num++;
//通知打印偶数
this.notify();
}
//打印偶数
public synchronized void printOu(){
//当num是奇数时需要等待
while (num % 2==1){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":"+num);
num++;
//通知打印奇数
this.notify();
}
}
class test09{
public static void main(String[] args) {
PrintNum printNum = new PrintNum();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
printNum.printJi();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
printNum.printOu();
}
}
}).start();
}
}