生产者消费者问题--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 ...
随机推荐
- .Net Core Linux部署
.Net Core是微软最新的开源框架跨平台框架 官网文档 .Net Core相关发布指令,以及发布RId便于查看 RID链接 .Net Core要想发布到Linux有俩种方案,分别是依赖框架的部署( ...
- IntelliJ IDEA 设置检查 serialVersionUID
IntelliJ IDEA 设置检查 serialVersionUID 背景介绍 我们在使用IntelliJ IDEA创建Java类的时候,有时候需要实现序列化接口 implements Serial ...
- Node、Document关系的探究
上图来自于<JavaScript权威指南(第六版)>P375 受到上图的启发,写了如下测试代码: var head = document.getElementsByTagName(&quo ...
- Android开发实例 Unity显示Toast
Android中的Toast是一种简易的消息提示框. 当视图显示给用户,在应用程序中显示为浮动.和Dialog不一样的是,它永远不会获得焦点,无法被点击.用户将可能是在中间键入别的东西.Toast类的 ...
- 面试题:检测一个ip的真实性,如果真实,确定其是不是在某一范围内
例题: 现有一个ip 10.2.1.71 ,检测该ip是否为真实有效的ip,并判断该ip是否在10.2.1.1——10.2.1.255之间 解题思路:用正则表达式检测ip的真实性,如果真实,将该ip转 ...
- 切换windows系统输入法的中英文,可以忽视是哪种打字法
调用windows的API //用户获取当前输入法句柄 [DllImport("imm32.dll")] public static extern IntPtr ImmGetCon ...
- CreateThread()使用实例
1.定义的全局变量 DWORD WINAPI ClientThread(LPVOID lpParam); struct ClientInfo { SOCKET sock; SOCKADDR_I ...
- (5.8)mysql高可用系列——MySQL中的GTID复制(实践篇)
一.基于GTID的异步复制(一主一从)无数据/少数据搭建 二.基于GTID的无损半同步复制(一主一从)(mysql5.7)基于大数据量的初始化 正文: [0]概念 [0.5]GTID 复制(mysql ...
- Java代码执行顺序及多态体现
/** * Description: * 基类的引用变量可以只想基类的实例对象也可指向其子类的事来对象 * 接口的引用变量也可以指向实现类的实例对象 * 程序调用的方法在运行期才动态绑定 * 绑定指将 ...
- java暂停线程
暂停线程 本节介绍两个被废弃的用于线程暂停和恢复的方法suspend().resume().主要探究废弃原因,强调线程的安全性.主要有两个原因 原因1: suspend().resume()使用不当, ...