// The standard idiom for calling the wait
synchronized(sharedObject) {
while(condition){
sharedObject.wait();// Releases lock, and reacquires on wake up
}
// do action based upon condition e.g. take or put into queue
}

使用wait和notify函数的规范代码模版。

在while循环里使用wait的目的:是在线程被唤醒前后都持续检查条件是否被满足,如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那个这个线程并不能保证被唤醒,有坑会导致死锁的问题。

 public class ProducerConsumer {
public static void main (String args[]) {
Queue<Integer> buffer = new LinkedList<>();
int maxSize = 10;
Thread producer = new Producer(buffer, maxSize, "PRODUCER");
Thread consumer = new Producer(buffer, maxSize, "CONSUMER");
producer.start();
consumer.start();
}
}

在上面代码中,声明了一个LinkedList作为缓冲区队列(在java中,LinkedList实现了队列的接口)。

class Producer extends Thread  {
private Queue<Integer> queue;
private int maxSize;
public Producer(Queue<Integer> queue, int maxSize, String name) {
super(name);
this.queue = queue;
this.maxSize = maxSize;
} @Override
public void run () {
while (true) {
synchronized (queue) { // 其它线程不能在我们检查条件时改变这个队列
while (queue.size() == maxSize) {
try {
// Queue is full
// Producer thread waiting for
// consumer to take something from queue
queue.wait();
} catch (Exception e) {
e.printStackTrace();
}
Random random = new Random();
int producerValue = random.nextInt();
queue.add(producerValue);
queue.notifyAll();
}
}
}
}
}

如上代码为生产者,其在无限循环中持续往LinkedList里插入随机整数直到LinkedList满。如果队列满了,那么生产者线程会在消费者线程消耗掉队列里的任意一个整数,并用notify通知生产者线程之前持续等待。

 class Consumer extends Thread {
private Queue<Integer> queue;
private int maxSize;
public Consumer (Queue<Integer> queue, int maxSize, String name ){
super(name);
this.queue = queue;
this.maxSize= maxSize;
}
@Override
public void run() {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
// queue is empty;
// Consumer thread is waiting
// for producer thread to put something in queue
try {
queue.wait();
} catch (Exception e) {
e.printStackTrace();
}
print("Consumer value : " + queue remove());
queue.notifyAll();
}
}
}
}
}

注意:

1. 你可以使用wait和notify函数来实现线程间通信,你可以用它们来实现多线程之间的通信。

2. 永远在synchronized的函数或者对象里使用wait、notify、notifyAll,不然java虚拟机会生成IllgalMonitorStateException。

3. 永远在while循环里而不是在if语句下使用wait,这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。

4. 永远在多线程间共享的对象(生产者消费者模型里即缓冲区队列)上使用wait。

Producer - Consumer Pattern:

Consumer:

sunchronized (obj) {
while (!workToDo) {
obj.wait();
}
// get next item from this queue
workToDo = false;
}
// do work on the item

Producer:

 synchronized (obj) {
if (!workToDo) {
// add work to queue
workToDo = true;
}
obj.notifyAll();
}

Java 生产者模式 消费者模式的更多相关文章

  1. java生产者与消费者模式

    前言: 生产者和消费者模式是我们在学习多线程中很经典的一个模式,它主要分为生产者和消费者,分别是两个线程, 目录 一:生产者和消费者模式简介 二:生产者和消费者模式的实现 声明:本例来源于java经典 ...

  2. Java并发编程(4)--生产者与消费者模式介绍

    一.前言 这种模式在生活是最常见的,那么它的场景是什么样的呢? 下面是我假象的,假设有一个仓库,仓库有一个生产者和一个消费者,消费者过来消费的时候会检测仓库中是否有库存,如果没有了则等待生产,如果有就 ...

  3. Java多线程设计模式(2)生产者与消费者模式

    1 Producer-Consumer Pattern Producer-Consumer Pattern主要就是在生产者与消费者之间建立一个“桥梁参与者”,用来解决生产者线程与消费者线程之间速度的不 ...

  4. java 线程并发(生产者、消费者模式)

    线程并发协作(生产者/消费者模式) 多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”. Ø 什么是生产者? 生产者指的是负责生产数 ...

  5. java进阶(40)--wait与notify(生产者与消费者模式)

    文档目录: 一.概念 二.wait的作用 三.notify的作用 四.生产者消费者模式 五.举例 ---------------------------------------分割线:正文------ ...

  6. 使用libuv实现生产者和消费者模式

    生产者和消费者模式(Consumer + Producer model) 用于把耗时操作(生产线程),分配给一个或者多个额外线程执行(消费线程),从而提高生产线程的响应速度(并发能力) 定义 type ...

  7. condition版生产者与消费者模式

    1.简介 在爬虫中,生产者与消费者模式是经常用到的.我能想到的比较好的办法是使用redis或者mongodb数据库构造生产者消费者模型.如果直接起线程进行构造生产者消费者模型,线程容易假死,也难以构造 ...

  8. 【爬虫】Condition版的生产者和消费者模式

    Condition版的生产者和消费者模式 threading.Condition 在没有数据的时候处于阻塞状态,有数据可以使用notify的函数通知等等待状态的线程运作 threading.Condi ...

  9. 【爬虫】Load版的生产者和消费者模式

    ''' Lock版的生产者和消费者模式 ''' import threading import random import time gMoney = 1000 # 原始金额 gLoad = thre ...

  10. Java生产者与消费者(上)

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 生产与消费者模式,是编程中最常用的模式之一,在多线程中应用比较明显.个人理解:在自助餐厅,厨师在不断 ...

随机推荐

  1. CLR via C#(15)--String,熟悉而又陌生

    好久没写文章了,再拿起这本书,学习加分享,乐趣无穷啊.这两天看了写关于字符串的知识,从学写代码的时候开始,我们就基本天天跟String打交道,对它再熟悉不过了.但是仔细看看,还是有一种拨开云雾的感觉, ...

  2. 16.迭代器模式(Iterator Pattern)

    using System; namespace ConsoleApplication9 { class Program { /// <summary> /// 迭代器模式提供了一种方法顺序 ...

  3. 用#define来实现多份近似代码 - map,set中的应用

    在stl中map,set内部都是使用相同的红黑树实现,map对应模板参数key_type,mapped_type,而set对应模板参数没有mapped_type 两者都支持insert操作 pair& ...

  4. 菜鸟学Linux命令:nohup命令启动程序

    在UNIX/LINUX中,普通进程用&符号放到后台运行,如果启动该程序的控制台logout,则该进程随即终止. 要实现守护进程,一种方法是按守护进程的规则去编程,比较麻烦:另一种方法是仍然用普 ...

  5. SQL脚本书写的几点建议

    1.索引很关键,创建合理的索引,提升查询速度:            DBCC FREEPORCCACHE       DBCC DROPCLEANBUFFERS                    ...

  6. mysql 如何设置自动增长序列 sequence(一)

    背景:由于项目需要,必须用mysql设置主键自增长,而且想用字符串的.经过上网查找并且实验,终于做出了一套方案.现在就共享给大家! 解决思路:由于mysql不带sequence,所以要手写的,创建一张 ...

  7. WebBrowser控件打开https站点

    背景: 与上一篇博文一样,此文亦是由于开发DropboxAPI中遇到问题衍生出来的.由于需要重定向https类型网站,但自己的https证书是自签名的,总是提示'网站的安全证书存在问题'. 鉴此,查了 ...

  8. JS自定义属性兼容

    var obj={}; if(obj.dataset){ obj.dataset.original="11"; }else{ obj.getAttribute("data ...

  9. 对于一个负数mod正数

    鸟神说.. a/b靠零取整 然后呢..a%b定义成a-(a/b)*b c语言就是这么算的... 那么python2.6是怎么算的呢 如果最后你取模想得到一个正数.. 那么在上述取模定义不变的情况下 p ...

  10. 金融左侧js错误