Java多线程(5)——生产者消费者模式实践

原创 2017年01月15日 22:26:39

生产者消费者模式:生产者和消费者要处理同一货物对象,货物对象的属性对生产者和消费者的行为应该产生制约,即有货物才能消费,没有货物就进行生产。通过同步方法,wait()休眠线程,和notify或者notifyall唤醒线程来实现这个逻辑,详情见下面代码:

货物:

package com.way.threads.consumerandproducer;

public class Goods {

    private String name;
    private int num=0;
    private boolean havegoods=false;//用来标记是否有货物的flag

    public synchronized void produce(String name){
        if(havegoods){
            try {
                this.wait();//等待其他进程运行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.name=name;
        this.num++;
        System.out.println("Produce "+name+" num: "+num);

        this.havegoods=true;//设置flag
        this.notify();    //唤醒线程

    }

    public synchronized void consume(){
        if(!havegoods){
            try {
                this.wait();//等待其他进程运行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        this.num--;
        System.out.println("Consume "+name+" num: "+num);

        this.havegoods=false;
        this.notify();   //唤醒线程
    }
}

生产者

package com.way.threads.consumerandproducer;

public class Producer implements Runnable{
    //生产者,负责生产货物
    private Goods goods;

    public Producer(Goods goods){
        super();
        this.goods=goods;

    }

    public void run() {
        for(int i=0;i<20;i++){
            if(i%2==0){
               goods.produce("bike"); 
            }else{
                goods.produce("car");
            }
        }
    }

}

消费者

package com.way.threads.consumerandproducer;

public class Consumer implements Runnable{
    //消费者,负责消费货物
    private Goods goods;

    public Consumer(Goods goods){
        super();
        this.goods=goods;
    }

    public void run() {

        for(int i=0;i<20;i++){
            goods.consume();
        }
    }

}

测试

package com.way.threads.consumerandproducer;

public class App {

    public static void main(String[] args){
        Goods goods=new Goods();
        //生产消费同时进行,必须保证有商品的时候才能被消费
        Consumer consumer=new Consumer(goods);
        Producer producer=new Producer(goods);

        new Thread(producer).start();
        new Thread(consumer).start();

    }
}

这个实现是货物只能存在一个,消费一个生产一个,实际也可以可以同时存在多个,那也就变成了“池”,可以对代码进行修改实现。代码如下:

货物:

package com.way.threads.consumerandproducer;

public class Goods {

    private int num=0;

    public synchronized void produce(){
        if(isFull()){
            try {
                this.wait();//等待其他进程运行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if(!isFull()){
            this.num++;
            System.out.println(Thread.currentThread().getName().toString()+" Produce "+" num: "+num);
            try {
                wait(500);//这里是为了让效果明显,不然太快了,看不出线程的切换
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        notifyAll();

    }

    public synchronized void consume(){
        if(isEmpty()){
            try {
                this.wait();//等待其他进程运行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if(!isEmpty()){
            this.num--;
            System.out.println(Thread.currentThread().getName().toString()+" Consume "+" num: "+num);
            try {
                wait(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }
        notifyAll();
    }

    public boolean isEmpty(){
        if(num<=0){
            return true;
        }else{
            return false;
        }
    }

    public boolean isFull(){
        if(num>=10){
            return true;
        }else{
            return false;
        }
    }
}

生产者

package com.way.threads.consumerandproducer;

public class Producer implements Runnable{
    //生产者,负责生产货物
    private Goods goods;

    public Producer(Goods goods){
        super();
        this.goods=goods;

    }

    public void run() {
        for(int i=0;i<100;i++){
            goods.produce();
        }
    }

}

消费者

package com.way.threads.consumerandproducer;

public class Consumer implements Runnable{
    //消费者,负责消费货物
    private Goods goods;

    public Consumer(Goods goods){
        super();
        this.goods=goods;
    }

    public void run() {

        for(int i=0;i<100;i++){
            goods.consume();
        }
    }   
}

测试

package com.way.threads.consumerandproducer;

public class App {

    public static void main(String[] args){
        Goods goods=new Goods();
        //生产消费同时进行,必须保证有商品的时候才能被消费
        Consumer consumer=new Consumer(goods);
        Consumer consumer2=new Consumer(goods);
        Consumer consumer3=new Consumer(goods);
        Producer producer=new Producer(goods);
        Producer producer2=new Producer(goods);
        Producer producer3=new Producer(goods);
        new Thread(producer).start();
        new Thread(consumer).start();
        new Thread(consumer2).start();
        new Thread(producer2).start();
        new Thread(consumer3).start();
        new Thread(producer3).start();

    }
}

这里启动了多个生产者和消费者线程,为了更好地展示效果。

部分结果:

Thread-1 Consume  num: 2
Thread-3 Produce  num: 3
Thread-5 Produce  num: 4
Thread-4 Consume  num: 3
Thread-2 Consume  num: 2
Thread-0 Produce  num: 3
Thread-2 Consume  num: 2
Thread-4 Consume  num: 1
Thread-5 Produce  num: 2
Thread-3 Produce  num: 3
Thread-1 Consume  num: 2
Thread-3 Produce  num: 3
Thread-5 Produce  num: 4
Thread-4 Consume  num: 3
Thread-2 Consume  num: 2
Thread-0 Produce  num: 3
Thread-2 Consume  num: 2

可以发现,生产和消费在持续进行着

其他实现方式:

java中实现生产者消费者模式:
最简单的方式是基于Object类的wait()/notify()方法实现:
wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。
notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

第二种方式是使用Lock的lock和unlock方法以及Condition相关的await()/signal()方法
使用与wait()/notify()类似
无论是生产者还是消费者,在lock()对“货物”加锁后,根据“容量”条件,使用await()阻塞线程,使用signal()唤醒其他等待线程,最后使用unlock()释放锁。

还可以使用BlockingQueue阻塞队列方法:
BlockingQueue是一个内部实现了同步机制的类,调用其put()和take()方法可以轻松实现生产者消费者模式:
put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。
take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。

版权声明:都是学习笔记,主要给自己看的,有误不负责,欢迎随便用

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

介绍了生产者消费者模式以及实现方法(wait¬ify,阻塞队列
  • antony9118
  • antony9118
  • 2016年05月23日 15:15
  • 2622

java 多线程并发系列之 生产者消费者模式的两种实现

生产者消费者模式是并发、多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。 真实世界中的生产者消费者模式...
  • yujin753
  • yujin753
  • 2015年05月14日 16:59
  • 11799

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

需求要求:使用2个线程,分别代表:生产者、消费者。让他们并发的去生产、消费产品。生产的总数是不能超过N的。实现思路这里我们使用的是使用信号量去控制线程的生产消费,通过释放令牌的形式去控制生产者消费者的...
  • qq_24489717
  • qq_24489717
  • 2017年04月12日 21:53
  • 812

Java多线程之简单生产者和消费者例子

一,在本例子中,有三个类,dataStore(存放数据类),consumer(消费者),producer(生产者)。 二,看源码例子: 类dataStore: import java.lang....
  • ganpengjin1
  • ganpengjin1
  • 2015年04月18日 15:13
  • 1899

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

前言:      在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序...
  • li12412414
  • li12412414
  • 2017年01月17日 09:34
  • 1425

多线程经典案例——生产者/消费者问题的Java实现与详解

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共...
  • shengwusuoxi
  • shengwusuoxi
  • 2014年04月01日 12:37
  • 2619

java多线程-专题-聊聊并发(十)生产者消费者模式

本文首发于InfoQ   作者:方腾飞  校对:张龙 在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。 为...
  • L25000
  • L25000
  • 2015年07月27日 10:46
  • 1126

java模拟生产者与消费者问题(线程同步)

关于生产者与消费者的问题,百度百科上的定义是这样的:生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在...
  • hl17200178
  • hl17200178
  • 2016年10月04日 23:32
  • 1911

Java多线程编程中生产者-消费者模式的详解

生产者-消费者模式是一个经典的多线程设计模式,它为多线程的协作提供了良好的解决方案。在生产者-消费者模式中,通常有两类线程,即若干个生产者线程和若干个消费者线程。生产者线程负责提交用户请求,消费者线程...
  • ghuiL
  • ghuiL
  • 2014年11月12日 15:24
  • 7023

线程同步经典案例-生产者与消费者模型-Java

一、相关知识简介      在生产者-消费者模型中,若只使用synchronized关键字实现对象锁,程序在运行中可能会出现以下两种情况: 若生产者的速度大于消费者,那么在消费者来不及取前一个数据之前...
  • Xminyang
  • Xminyang
  • 2016年11月18日 15:58
  • 1019
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java多线程(5)——生产者消费者模式实践
举报原因:
原因补充:

(最多只允许输入30个字)