文档章节

Java 多线程——生产者与消费者

雨中人X
 雨中人X
发布于 2016/12/11 15:50
字数 854
阅读 29
收藏 2

Java 多线程——生产者与消费者

生产者消费者问题是一个典型的线程同步问题,需要满足以下条件

  1. 生产者将物品放置到一个队列中,消费者按顺序取走
  2. 当队列满时,生产者需要停止生产,当队列为空时,消费者只能等待
  3. 当生产者向队列中加入产品时,需要通知消费者。当消费者取走物品时,需要通知生产者

原理

  • 入队操作
synchronized(this){
    while(!cond){
        wait()    
    }
    add(e)
    notifyAll()
}
  • 出队操作
synchronized(this){
    while(!cond){
        wait()    
    }
   poll()
   notifyAll()
}

注:此处的判断条件不能使用if,避免线程被唤醒时不满足条件。故线程被唤醒后需要 再次检查条件,看是否满足条件。当存在多个消费者线程和生产者线程时,线程被唤醒时 就可能不满足条件。读者可以自己尝试,多个消费者和生产者时使用if进行判断,会出现什么现象

Java实现

下面看一下Java代码实现

Factory.java 使用了Java的ArrayDeque 实现同步队列

package com.hive;

import java.util.ArrayDeque;
import java.util.Queue;

/**
 * Created by albert on 16-12-11.
 */
public class Factory {
    private final static int MAX_SIZE = 10;
    private Queue<String> pool;

    public Factory() {
        pool = new ArrayDeque<>();
    }

    synchronized public String poll() {
        while (pool.size() == 0) {    // 此处不应用 if判断,避免被错误唤醒
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        notifyAll(); // 通知生产者线程
        return pool.poll();
    }

    synchronized public void add(String e) {
        while (pool.size() > MAX_SIZE) {   // 此处不应用 if判断,避免被错误唤醒
            try {
                wait();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
        pool.add(e);
        notifyAll(); // 通知消费者线程
    }
}

Producer.java 生产者类

package com.hive;

import java.lang.String;

/**
 * Created by albert on 16-12-11.
 */
public class Producer implements Runnable {
    private String name;
    private Factory goods;

    public Producer(String name, Factory goods) {
        this.name = name;
        this.goods = goods;
    }


    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 20; i++) {
                System.out.println(name + " yield " + i);
                goods.add(name + ">" + i);
                try {
                    Thread.sleep(1 * 100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Customer.java 消费者类

package com.hive;

/**
 * Created by albert on 16-12-11.
 */
public class Customer implements Runnable {
    private String name;
    private Factory goods;

    public Customer(String name, Factory goods) {
        this.name = name;
        this.goods = goods;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(name + " use " + goods.poll());
            try {
                Thread.sleep(10 * 100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Main.java 测试方法

package com.hive;

public class Main {

    public static void main(String[] args) {
        Factory goods = new Factory();
        Producer p1 = new Producer("P1", goods);
        Producer p2 = new Producer("P2", goods);
        Customer c1 = new Customer("C1", goods);
        Customer c2 = new Customer("C2", goods);
        new Thread(p1).start();
        new Thread(p2).start();
        new Thread(c1).start();
        new Thread(c2).start();
    }
}

## 运行结果

P1 yield 0
P2 yield 0
C1 use P1>0
C2 use P2>0
P1 yield 1
P2 yield 1
P1 yield 2
P2 yield 2
P1 yield 3
P2 yield 3
P1 yield 4
P2 yield 4
P1 yield 5
P2 yield 5
P1 yield 6
P2 yield 6
P2 yield 7
C1 use P1>1
C2 use P2>1
P2 yield 8
P1 yield 7
C1 use P1>2
C2 use P2>2
P1 yield 8
P2 yield 9
C1 use P1>3
C2 use P2>3
P2 yield 10
P1 yield 9
C2 use P2>4
C1 use P1>4
P1 yield 10
P2 yield 11
C2 use P1>5
C1 use P2>5
P1 yield 11
P2 yield 12
C2 use P2>6
C1 use P2>7
P1 yield 12
P2 yield 13
C2 use P1>6
C1 use P1>7
P2 yield 14
P1 yield 13
C2 use P2>8
C1 use P2>9

© 著作权归作者所有

共有 人打赏支持
雨中人X
粉丝 8
博文 57
码字总数 15326
作品 0
深圳
高级程序员
Java多线程生产者消费者实例

Java生产者消费者实例 设计:涉及到的类有食物、厨师、服务员、顾客以及测试类。厨师负责生产食物,服务员服务于顾客,顾客负责点餐以及吃饭。 技术点:Java多线程,线程安全(synchronized),...

cicadaT
2017/11/05
0
1
JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52714313 JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费...

Aduroidpc
2016/10/01
0
0
【转】15个顶级Java多线程面试题及回答

Java 线程面试问题   在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务...

一只死笨死笨的猪
2014/09/30
0
0
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
0
0
JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52724939 JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千! 经过了几...

Aduroidpc
2016/10/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

nginx 负载均衡

一.配置方式 1.轮询(默认) 优点:实现简单; 缺点:不考虑每台服务器处理能力 2.权重 weight默认是1。如果有多个配置权重的节点,比较相对值。 15:10,只代表访问8080端口的概率是访问908...

imbiao
25分钟前
0
0
jQuery学习笔记180923

jQuery 操作 CSS jQuery 拥有若干进行 CSS 操作的方法。我们将学习下面这些: addClass() - 向被选元素添加一个或多个类 removeClass() - 从被选元素删除一个或多个类 toggleClass() - 对被选...

颖伙虫
36分钟前
1
0
[python] colorama 模块 - 改变控制台输出文本的颜色

除了使用 PyQt 这样的图形化开发框架外,基本上 python 程序都是跑在控制台中的。很多时候,单纯使用黑白的文字不能很好地突出我们要显示的信息。有时候我们需要将错误的提示使用红色标注,而...

cometeme
41分钟前
1
0
Makefile 学习 2 - 基于若干 Blog 的汇总

基于若干 Blog 汇总的 makefile 教程 陈皓 https://blog.csdn.net/haoel/article/details/2886 Makefile 进阶 1. Makefile 中的内容 显式规则。显式规则说明了,如何生成一个或多的的目标文件...

公孙衍
57分钟前
1
0
NIO与BIO的区别、NIO的运行原理和并发使用场景

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的...

Java干货分享
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部