生产者消费者问题--synchronized
# 代码
public class App {
public static void main(String[] args) {
Depot depot = new Depot(100);
Producer producer = new Producer(depot);
Consumer consumer = new Consumer(depot);
producer.produce(60);
consumer.consume(100);
producer.produce(90);
consumer.consume(40);
}
}
class Depot {
// 仓库最大容量
private int capacity;
// 仓库目前容量
private int size;
public Depot(int capacity) {
this.size = 0;
this.capacity = capacity;
}
public synchronized void produce(int val) {
try {
int surplus = val;
while (surplus > 0) {
while (size >= capacity) {
wait();
}
int incre = (size + surplus) > capacity ? (capacity - size) : surplus;
size += incre;
surplus -= incre;
System.out.printf("%s plan to produce (%d), actually produce (%d), depot size (%d) \n",
Thread.currentThread().getName(), val, incre, size);
notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void consume(int val) {
try {
int surplus = val;
while (surplus > 0) {
while (size <= 0) {
wait();
}
int desc = (size < surplus) ? size : surplus;
size -= desc;
surplus -= desc;
System.out.printf("%s plan to consume (%d), actutally consume (%d), depot size (%d) \n",
Thread.currentThread().getName(), val, desc, size);
notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Producer {
private Depot depot;
public Producer(Depot depot) {
this.depot = depot;
}
public void produce(final int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
}
class Consumer {
private Depot depot;
public Consumer(Depot depot) {
this.depot = depot;
}
public void consume(final int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
}
# 输出:
Thread-0 plan to produce (60), actually produce (60), depot size (60)
Thread-3 plan to consume (40), actutally consume (40), depot size (20)
Thread-2 plan to produce (90), actually produce (80), depot size (100)
Thread-1 plan to consume (100), actutally consume (100), depot size (0)
Thread-2 plan to produce (90), actually produce (10), depot size (10)
# 有四个线程参与了这个过程,两个生产者,两个消费者
# 时隔多月,我们再来考虑一种业务场景,假设要求是,生产的时候的条件是:要么全部生产,要么全部不生产;消费的条件也是:要么全部消费,要么不消费;此时,实现的代码可能如下:
public class Common {
public static void main(String[] args) {
Depot depot = new Depot(100);
Producer producer = new Producer(depot);
Consumer consumer = new Consumer(depot);
for (int i = 0; i < 10; i++) {
producer.produce(50);
}
for (int i = 0; i < 50; i++) {
consumer.consume(10);
}
}
}
class Depot {
// 仓库最大容量
private int capacity;
// 仓库目前容量
private int size;
public Depot(int capacity) {
this.size = 0;
this.capacity = capacity;
}
public synchronized void produce(int val) {
try {
if (size + val > capacity) {
wait();
}
size += val;
System.out.printf("%s produce (%d), depot size (%d) \n", Thread.currentThread().getName(), val, size);
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void consume(int val) {
try {
if (size - val < 0) {
wait();
}
size -= val;
System.out.printf("%s consume (%d), depot size (%d) \n", Thread.currentThread().getName(), val, size);
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Producer {
private Depot depot;
public Producer(Depot depot) {
this.depot = depot;
}
public void produce(final int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
}
class Consumer {
private Depot depot;
public Consumer(Depot depot) {
this.depot = depot;
}
public void consume(final int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
}
- 运行一下,你会发现仓库中的数量会出现负的情况,如果你改变生产者和消费者的线程数,还有可能出现超过仓库容量的情况,这该怎么解决呢?
- 其实解决方法很简单,把wait()方法的判断语句由if换成while即可;
- 我们来深究原因,以消费者为例,if的情况下,消费线程由wait状态切换到运行状态的时候,不再去判断仓库中的现有的存储量是否满足消费,此时该消费线程有可能由其他的消费线程唤醒,而其他的线程早已经把仓库消费完了,该线程再去消费,仓库自然就变成负的了。而while则不同,判断条件为while时,每次消费者线程被唤醒,均会做一次判断。
- 其实在jdk文档中,对这种情况已经作了强调说明, 如下图所示

! 多读官方文档,多读源码! 手动笑哭。。。
生产者消费者问题--synchronized的更多相关文章
- 【多线程】--生产者消费者模式--synchronized版本
在实现生产者消费者模式之前,我们先了解一下线程的5种状态:被创建.运行.冻结.消亡.阻塞,如下图: 在Jdk1.5发布之前,我们实现生产者消费者模式一般使用synchronized + while循环 ...
- 多线程-生产者消费者(synchronized同步)
正解博客:https://blog.csdn.net/u011863767/article/details/59731447 永远在循环(loop)里调用 wait 和 notify,不是在 If 语 ...
- 【多线程】--生产者消费者模式--Lock版本
在JDK1.5发布后,提供了Synchronized的更优解决方案:Lock 和 Condition 我们使用这些新知识,来改进例子:[多线程]--生产者消费者模式--Synchronized版本 改 ...
- 生产者-消费者模型的3种Java实现:synchronized,signal/notifyAll及BlockingQueue
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3555111.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- java ReentrantLock结合条件队列 实现生产者-消费者模式 以及ReentratLock和Synchronized对比
package reentrantlock; import java.util.ArrayList; public class ProviderAndConsumerTest { static Pro ...
- Java 学习笔记 使用synchronized实现生产者消费者模式
说明 Object.wait()使当前的线程进入到等待状态(进入到等待队列) Object.notifyAll() 唤醒等待中的全部线程 Object.notify() 随机唤醒一个线程 代码 con ...
- java使用synchronized与Semaphore解决生产者消费者问题对比
一.synchronized与信号量Semaphore简介 1.synchronized是java中的关键字,是用来控制线程同步的问题最常用的方法. 2.Semaphore是属于java的一个类,同样 ...
- Java多线程-同步:synchronized 和线程通信:生产者消费者模式
大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...
- Java学习之线程通信(多线程(synchronized))--生产者消费者
分析线程经典案例生产者消费者 /** 共享数据 */ class Resource { private String name; private int count=1; private boolea ...
随机推荐
- 麦香牛肉(dp 、数论)
麦香牛肉 时间限制: 1 Sec 内存限制: 128 MB 题目描述 农夫约翰的奶牛几乎要武装暴动,因为他们听说麦当劳要推出新产品麦香牛肉.奶牛们要尽力阻止这种产品的上市.他们研究了一种“劣等包装” ...
- selenium知识思维导图|从元素定位到操作断言,助你快速入门自动化测试
为什么要进行自动化测试? 缩短测试周期,节省成本. 避免人为出错,提高准确性和可靠性. 获取需求覆盖率,代码覆盖率,提供衡量软件质量的指标. 自动化测试的条件? 手工测试完成后. 项目周期长,需求稳定 ...
- 【HANA系列】SAP HANA SQL从给定日期中获取分钟
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL从给定日 ...
- java内存模型的实现
前几天,发了一篇文章,介绍了一下JVM内存结构.Java内存模型以及Java对象模型之间的区别.其中,Java内存模型,是这三个知识点当中最晦涩难懂的一个,而且涉及到很多背景知识和相关知识. 网上有很 ...
- Rate Limiter
Whenever you expose a web service / api endpoint, you need to implement a rate limiter to prevent ab ...
- PLSQL中查到的数据和程序中查询到的不一样
1.首先看下你的修改或者新增的SQL是否提交.
- 【GDOI】2018题目及题解(未写完)
我的游记:https://www.cnblogs.com/huangzihaoal/p/11154228.html DAY1 题目 T1 农场 [题目描述] [输入] 第一行,一个整数n. 第二行,n ...
- thinkphp5.1 关于加载静态资源路径问题
和thinkphp5.0不一样,thinkphp5.1的 thinkphp5.0的 直接在config.php文件中加入代码: <?phpreturn [ 'view_replace_str' ...
- Zabbix-自带监控项与Kye
开启主机自动发现 ⦁选择配置 ->自动发现 ->创建自动发现->ip范围必须连续,不连续的话逗号分开 ⦁更新间隔 -> 2s ->更新 ⦁检查 -> 选择新的 -& ...
- 福建工程学院第十四届ACM校赛G题题解
外传:编剧说了不玩游戏不行 题意: 有n个石堆,我每次只能从某一堆中取偶数个石子,你取奇数个,我先手,先不能操作的人输.问最后谁能赢. 思路: 这个题仔细想想,就发现,取奇数的人有巨大的优势,因为假设 ...