生产者消费者模式的java实现(实现一)

在多线程以及并发工具类中,常用的一种思想就是生产者消费者模式,生产者负责生产物品,将物品放到传送带,消费者负责获取传送带的物品,消费物品。现在只考虑最简单的情况,传送带上只允许放一个物品。

1、传送带为空,则允许生产者放置物品,否则不许放(生产者线程wait)。

2、生产者放置完物品后,通知消费者可以拿了(线程通信,notify 或者notifyAll)。

2、传送带不空,则允许消费者拿物品,否则不许拿(消费者线程wait)。

3、消费者拿走物品后,通知生产者可以继续生产(线程通信,notify 或者notifyAll)。

package com.smikevon.concurrent;

import java.util.Random;

/**
 * @description: 生产者消费者模式,通过wait和notify方式来实现
 * @date       : 2014年9月12日 上午11:39:31
 */
public class ProducerConsumer_01 {

    public static void main(String[] args) {
        Drop drop = new Drop();
        new Thread(new Producer(drop)).start();
        new Thread(new Consumer(drop)).start();
    }

}

/**
 * @description: 传送带,只能有一个物品(message)在上面
 * @date       : 2014年9月12日 下午12:03:08
 */
class Drop{

    private String message;
    private boolean empty = true;

    public synchronized String take() throws InterruptedException{
        while(empty){
            wait();
        }
        empty = true;
        notifyAll();
        return message;
    }

    public synchronized void put(String message) throws InterruptedException{
        while(!empty){
            wait();
        }
        this.message = message;
        empty = false;
        notifyAll();
    }

}

/**
 *
 * @description: 生产者随机放入字符串
 * @date       : 2014年9月12日 上午11:53:27
 */
class Producer implements Runnable {

    private Drop drop;

    public Producer(Drop drop) {
        this.drop = drop;
    }

    public void run() {
        String[] messages = {
            "我是",
            "一名程序员",
            "我很骄傲",
            "也很自豪",
            "爱岗敬业",
            "勤劳奉献",
            "无怨无悔",
            "奉献青春",
            "希望通过学习",
            "提升",
            "自己",
            "done",
        };
        try {
            for(int i=0;i<messages.length;i++){
                System.out.format("%s: 放入信息-----------%s %n",Thread.currentThread().getName(),messages[i]);
                drop.put(messages[i]);
                Thread.sleep(new Random(System.currentTimeMillis()).nextInt(5000));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

/**
 * @description: 消费者,有字符串,就取出来
 * @date       : 2014年9月12日 下午12:02:35
 */
class Consumer implements Runnable{

    private Drop drop;

    Consumer(Drop drop){
        this.drop = drop;
    }

    public void run() {
        try {
            String message = "";
            System.out.println(drop);
            while(!(message = drop.take()).equals("done")){
                System.out.format("%s: 取出信息-------------%s %n",Thread.currentThread().getName(),message);
                Thread.sleep(new Random(System.currentTimeMillis()).nextInt(5000));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

在线程wait的代码处都采用了循环测试条件(专业名称叫条件谓词),如下

while(!empty){
            wait();
        }

  是因为在另一个线程notifyAll,唤醒本线程后,无法确认此时就一定满足测试条件。两个线程不会有问题,但是在更多线程的时候就会出问题,因为你无法确认自己就是被生产者线程唤醒的,可能在唤醒之前已经有其他线程改变过状态变量(本类就是Drop里的message),这样就会出现异常,因此需要在被唤醒后立马测试下条件是否已经满足。将一致性保障交给竞态条件(notifyAll就是等待的线程竞争获取对象的锁)是不良的变成习惯。

  下面一节(实现二)会介绍ReenrantLock,里面将等待与唤醒条件进行了细分,让你可以赋予条件真实的意义,而不只将意义绑定到锁的持有上(wait是告诉本线程挂起 和 notify就是告知线程可以抢占对象内置锁了)。

时间: 2024-08-11 23:31:19

生产者消费者模式的java实现(实现一)的相关文章

生产者消费者模式的java实现(实现三)

Exchanger是java.util.concurrent类库下的一个并发工具.下面是java api文档里对Exchanger的描述. A synchronization point at which threads can pair and swap elements within pairs. Each thread presents some object on entry to the exchange method, matches with a partner thread, a

生产者消费者模式的java实现(实现二)

这次采用ReentrantLock 实现生产者消费者模式,先说下ReentrantLock,通常叫做重入锁,所谓重入就是一个线程可以再次进入已经持有锁的代码块,在内部会对重入的次数进行计数,当计数为0,则释放锁.其实synchronized关键字所代表的内置锁,也是可以重入的.但是又有几点不同: 1.ReentrantLock将加锁与解锁进行分离,可以提供更细粒度的加解锁操作,内置锁基本都是全局锁(类,对象,代码块) 2.ReentrantLock提供了定时的加锁操作,这是内置锁无法做到的. 3

并发编程基础之生产者消费者模式

一:概念 生产者消费者模式是java并发编程中很经典的并发情况,首先有一个大的容器,生产者put元素到 容器中,消费者take元素出来,如果元素的数量超过容器的容量时,生产者不能再往容器中put元素 ,处于阻塞状态,如果元素的数量等于0,则消费者不能在从容器中take数据,处于阻塞状态. 二:示例 /** * */ package com.hlcui.main; import java.util.LinkedList; import java.util.concurrent.ExecutorSe

Java 并发编程(四)阻塞队列和生产者-消费者模式

阻塞队列 阻塞队列提供了可阻塞的 put 和 take 方法,以及支持定时的 offer 和 poll 方法.如果队列已经满了,那么put方法将阻塞直到有空间可以用:如果队列为空,那么take方法将一直阻塞直到有元素可用.队列可以使有界的,也可以是无界的,无界队列永远都不会充满,因此无界队列上的put方法永远不会阻塞.一种常见的阻塞生产者-消费者模式就是线程池与工作队列的组合,在 Executor 任务执行框架中就体现了这种模式. 意义:该模式能简化开发过程,因为他消除了生产者和消费者类之间的代

java设计模式之生产者/消费者模式

什么是生产者/消费者模式? 某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.线程.进程等).产生数据的模块,就形象地称为生产者:而处理数据的模块,就称为消费者.在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模式.结构图如下: 生产者消费者模式有如下几个优点: 1.解耦   由于有缓冲区的存在,生产者和消费者之间不直接依赖,耦合度降低. 2.支持并发   由于生产者与消费

Java线程同步与死锁、生产者消费者模式以及任务调度等

一.Thread类基本信息方法 package Threadinfo; public class MyThread implements Runnable{ private boolean flag = true; private int num = 0; @Override public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"-->"+num++); } }

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

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式. 什么是生

java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现

java多线程15 :wait()和notify() 的生产者/消费者模式 在这一章已经实现了  wait/notify 生产消费模型 利用await()/signal()实现生产者和消费者模型 一样,先定义一个缓冲区: public class ValueObject { public static String value = ""; } 换种写法,生产和消费方法放在一个类里面: public class ThreadDomain41 extends ReentrantLock {

Java并发(基础知识)—— 阻塞队列和生产者消费者模式

1.阻塞队列 BlockingQueue是线程安全的Queue版本,从它的名字就可以看出,它是一个支持阻塞的Queue实现:当向空BlockingQueue请求数据时,它会阻塞至BlockingQueue非空:当向一个已满BlockingQueue插入数据时,线程会阻塞至BlockingQueue可插入. BlockingQueue 的方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或 fa