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技术深入(一)——java多线程(七)——阻塞队列,生产者-消费者模式

1、阻塞队列(BlockingQueue)适合用来实现生产者-消费者模式。生产者线程会将向阻塞队列中填充数据,消费者会从阻塞队列中取出数据并用于运算。阻塞队列会自动地进行平衡负载。如果生产的速度快于消...

Java实践之路——多线程之生产者消费者模型

一、环境 1、平台:MyEclipse8.5/JDK1.5 二、概述 1、目标:用java实现生产者消费者模型 2、生产者消费者模型描述 1)、生产者仅仅在仓储未满时候生产,仓满则停止生...
  • CYXLZZS
  • CYXLZZS
  • 2012年09月25日 11:25
  • 884

Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_c...

Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

Posix信号量Posix 信号量有名信号量无名信号量sem_opensem_initsem_closesem_destroysem_unlink sem_waitsem_post 有名信号量#inc...

多线程——用Lock(锁)和Condition(监听器)来优化生产者消费者模式(进一步优化,解决可能产生的死锁问题)

package com.qianfeng.demo02 ; import java.util.concurrent.locks.Condition; import java.util.concurr...

多线程——用Lock(锁)和Condition(监听器)来优化生产者消费者模式

package com.qianfeng.demo02; import java.util.concurrent.locks.Condition; import java.util.concurre...

多线程——等待唤醒机制经典实例:生产者消费者模式(优化)

package com.work.wor01; /** * 等待唤醒机制经典实例:生产者消费者模式。 * * 当使用多个生成者线程,多个消费者线程时,会出现线程不安全的现象,即使是同步了,也不...

多线程学习——生产者消费者模式练习

作为新手,学习了一下多线程,练习了一下生产者/消费者模式的简单实现,做个笔记,好加深印象,以后也好复习。...

多线程——等待唤醒机制经典实例:生产者消费者模式

package com.qianfeng.demo04; /** * 。 * */ //资源 class Resource{ private String name; private int ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java多线程(5)——生产者消费者模式实践
举报原因:
原因补充:

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