关闭

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

标签: java线程java多线程java多线程模式
213人阅读 评论(0) 收藏 举报
分类:

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多线程设计模式》的学习笔记整理和自己的理解。

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

0
0
查看评论

如何实现生产者消费者模式

生产/消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”、“消费者”、“仓库”和“产品”。他们之间的关系如下: ① 生产者仅仅在仓储未满时候生产,仓满则停止生产。 ② 消费者仅仅在仓储有产品时候才能消费,仓空则等待。 ③ 当消费者发现仓库没产品可消费时候会通知生产者生产。 ④ 生...
  • u010339647
  • u010339647
  • 2016-07-24 11:33
  • 4230

Java多线程--生产者消费者模型(Semaphore实现)

需求要求:使用2个线程,分别代表:生产者、消费者。让他们并发的去生产、消费产品。生产的总数是不能超过N的。实现思路这里我们使用的是使用信号量去控制线程的生产消费,通过释放令牌的形式去控制生产者消费者的上限。使用互斥锁保证每次最多只有一个角色去修改共享变量。来看张图,一图胜千言。 代码实现代码的注释...
  • qq_24489717
  • qq_24489717
  • 2017-04-12 21:53
  • 812

JAVA多线程(三)生产者消费者模式及实现方法

介绍了生产者消费者模式以及实现方法(wait&notify,阻塞队列
  • antony9118
  • antony9118
  • 2016-05-23 15:15
  • 2620

生产者/消费者模式之深入理解

★简介    在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。    ...
  • sanyuesan0000
  • sanyuesan0000
  • 2016-11-01 15:52
  • 2443

Java多线程-工具篇-BlockingQueue(实现生产者和消费者模式)

前言:      在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。本文详细介绍了BlockingQueue家庭中的所有成...
  • li12412414
  • li12412414
  • 2017-01-17 09:34
  • 1424

redis 队列 生产者 消费者模式

1. 生产者: <?php //publish.php $redis = new Redis(); $redis->pconnect('10.10.10.252',6379); $redis->auth('rds!2016!FD...
  • terry_water
  • terry_water
  • 2015-12-29 12:29
  • 4818

JAVA 生产者消费者模式的实现

一、明确定义 要理解生产消费者问题,首先应弄清PV操作的含义:PV操作是由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:     P(S):①将信号量S的值减1,即S=S-1;     ...
  • ftx2540993425
  • ftx2540993425
  • 2016-03-07 16:33
  • 1082

Java设计模式—生产者消费者模式(阻塞队列实现)

生产者消费者模式是并发、多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。这篇文章我们来看看什么是生产者消费者模式,这个问题也是多线程面试题中经常被提及的。如何使用阻塞队列(Blocking Queue)解决生产者消费...
  • zljjava
  • zljjava
  • 2015-08-07 15:01
  • 3612

Java实现生产者消费者模型

生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步;(2)在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易...
  • ILOVESMJ
  • ILOVESMJ
  • 2016-09-19 17:07
  • 6521

关于生产者/消费者/订阅者模式的那些事

生产者/消费者模式简介用来干嘛的?生产者/消费者模式的产生主要目的就是为了解决非同步的生产与消费之间的问题。什么是非同步呢? 比如我刚刚生产了某个产品,而此时你正在打游戏,没空来取,要打完游戏来取,这就导致了我生产产品和你取产品是两个非同步的动作,你不知道我什么时候生产完产品,而我也不知道...
  • u010687392
  • u010687392
  • 2016-01-27 14:17
  • 2188
    个人资料
    • 访问:36932次
    • 积分:877
    • 等级:
    • 排名:千里之外
    • 原创:53篇
    • 转载:0篇
    • 译文:0篇
    • 评论:3条
    最新评论