Java多线模式-Producer-Consumer模式(生产者、消费者模式)

1.场景
有些时候需要两个或两个以上的线程协同工作,每个线程需要使用其他线程产生数据。

2.详细说明
可以把上面的场景抽象成生产者和消费者模式。从消费者的角度:消费者需要消费生产者生成的产品。
从生产者的角度:生产者需要将生产的产品安全地交给消费者。这虽然看着是一个简单的操作。但如果生产者和消费者在不同的线程中运行,两者之间的处理速度差异会引起问题:消费者消费的速度远快于生产者生产的速度即消费者想要获取数据,而数据还没有产生,或者消费者消费的速度远慢于生产者生产的速度即生产者想要交付数据时,消费者还处在无法接收数据的状态。

3.Producer-Consumer模式
Producer-Consumer模式在生产者和消费者中间加入”桥梁角色”。利用该角色来消除不同线程间的处理速度的差异。


要实现上述的场景,我们设计这样一个场景:
在一家制作蛋糕店里,糕点师制作蛋糕,并将蛋糕放在桌子上。顾客按顺序从桌子上拿蛋糕吃。、
说明:1.桌子上最多只能放3个蛋糕;2.若桌子已经放满3个蛋糕,糕点师必须等到桌子空出位置才能放置蛋糕;3.如果桌子上没有蛋糕,顾客必须等待桌子上有蛋糕才能吃。

因此我们需要设计4个类:糕点师类MakerThread,顾客类EaterThread,桌子类Table,启动线程的主类Main。类图如下:
这里写图片描述
源码如下:

public class Table {
    private final String[] buffer;
    private int tail;//下次put的位置
    private int head;//下次take的位置
    private int count;//buffer中蛋糕的个数
    public Table(int count){
        this.buffer=new String[count];
        this.head=0;
        this.tail=0;
        this.count=0;
    }
    //放置产品(蛋糕)
    public synchronized void addCake(String cake) throws InterruptedException {
        StdOut.println(Thread.currentThread().getName()+" puts "+cake);
        while(count>=buffer.length){
            wait();
        }
        buffer[tail]=cake;
        tail=(tail+1)%buffer.length;
        count++;
        notifyAll();
    }
    //拿取蛋糕
    public  synchronized String reduceCake() throws InterruptedException{
        while(count<=0){
            wait();
        }
        String cake=buffer[head];
        head=(head+1)%buffer.length;
        count--;
        notify();
        StdOut.println(Thread.currentThread().getName()+" takes "+cake);
        return cake;
    }

}

在Table类中我们采用数组来存放蛋糕,同时设计两个方法:addCake()和reduceCake()来对桌子上蛋糕数量等状态进行修改。
在addCake()中线程的守护条件是:count>=buffer.length;如果满足该条件则表示桌子已放满蛋糕,糕点师需要等待,直到桌子空出位置,才能放置。
在reduceCake()中线程的守护条件是:count<=0;如果满足该条件则表示桌子已经没有蛋糕了,顾客需要等待,等到桌子上有蛋糕时才能吃。

糕点师类:

public class MakerThread extends Thread {
    private final Random random;
    private final Table table;
    private static int id=0;//蛋糕的流水号

    public MakerThread(String name,Table table,long seed){
        super(name);
        this.table=table;
        this.random=new Random(seed);
    }
    public void run(){
        try {
            while(true){
                Thread.sleep(random.nextInt(1000));
                String cake="[ Cake No."+nextId()+" by "+getName()+" ]";
                table.addCake(cake);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    private static synchronized int nextId(){
        return id++;
    }
}

顾客吃蛋糕类:

public class EaterThread extends Thread {
    private final Random random;
    private final Table table;
    public EaterThread(String name,Table table,long seed){
        super(name);
        this.table=table;
        this.random=new Random(seed);
    }
    public void run(){
        try {
            while(true){
                Thread.sleep(random.nextInt(1000));
                String cake=table.reduceCake();

            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

启动线程类:

public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Table table=new Table(3);//创建一个能放置3个蛋糕的桌子
        new MakerThread("MakerThread-1", table, 31415).start();
        new MakerThread("MakerThread-2", table, 31415).start();
        new MakerThread("MakerThread-3", table, 31415).start();
        new EaterThread("EaterThread-1", table, 161415).start();
        new EaterThread("EaterThread-2", table, 71415).start();
        new EaterThread("EaterThread-3", table, 81415).start();
    }
}

说明:学习《图解java多线程设计模式》的学习笔记整理和自己的理解。

更多技术干货,请关注下面二维码:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脑机接口社区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值