文档章节

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

雨中人X
 雨中人X
发布于 2016/12/11 15:50
字数 854
阅读 30
收藏 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
java中高级大公司多线程面试题

1)在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? lock接口在多线程和并发编...

java成功之路
10/30
0
0
【转】15个顶级Java多线程面试题及回答

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

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

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

LCZ777
2014/05/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

&和&&,==和equals的区别

&和&& 相同点:都可以表示逻辑与(and),当运算符两边的结果都为true时,结果才为true,只要有一边为false,结果就为false。 不同点:&&还有短路的作用,即如果第一个表达式的结果为false,就...

森林之下
29分钟前
2
0
我和 Spring 大神的一天

摘要: 先介绍一下故事的5位主人公。 Josh Long 龙之春:Spring 技术布道师,撰写过5部著作,录制过3部畅销的培训视频,是一位开源软件贡献者。 Spencer Gibb:Spring 技术布道师,Spring Cl...

阿里云官方博客
32分钟前
2
0
【Zookeeper】源码分析目录(保存)

https://www.cnblogs.com/leesf456/p/6518040.html

Java搬砖工程师
35分钟前
2
0
vue-cli图片路径使用

https://www.cnblogs.com/minigrasshopper/p/8011630.html

LM_Mike
35分钟前
2
0
前方高能,重要通知!明珠不蒙尘,有才你就来。

11月开源众包服务之星计划--开发商招募正式开启了! 您还是否在为能接更多的订单而操碎了心? 开源众包即将迎来三周年华诞,重磅上线服务之星品牌计划。你有强大的技术实力?你有丰富的案例经...

开源中国众包平台
37分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部