# 代码

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的更多相关文章

  1. 【多线程】--生产者消费者模式--synchronized版本

    在实现生产者消费者模式之前,我们先了解一下线程的5种状态:被创建.运行.冻结.消亡.阻塞,如下图: 在Jdk1.5发布之前,我们实现生产者消费者模式一般使用synchronized + while循环 ...

  2. 多线程-生产者消费者(synchronized同步)

    正解博客:https://blog.csdn.net/u011863767/article/details/59731447 永远在循环(loop)里调用 wait 和 notify,不是在 If 语 ...

  3. 【多线程】--生产者消费者模式--Lock版本

    在JDK1.5发布后,提供了Synchronized的更优解决方案:Lock 和 Condition 我们使用这些新知识,来改进例子:[多线程]--生产者消费者模式--Synchronized版本 改 ...

  4. 生产者-消费者模型的3种Java实现:synchronized,signal/notifyAll及BlockingQueue

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3555111.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  5. java ReentrantLock结合条件队列 实现生产者-消费者模式 以及ReentratLock和Synchronized对比

    package reentrantlock; import java.util.ArrayList; public class ProviderAndConsumerTest { static Pro ...

  6. Java 学习笔记 使用synchronized实现生产者消费者模式

    说明 Object.wait()使当前的线程进入到等待状态(进入到等待队列) Object.notifyAll() 唤醒等待中的全部线程 Object.notify() 随机唤醒一个线程 代码 con ...

  7. java使用synchronized与Semaphore解决生产者消费者问题对比

    一.synchronized与信号量Semaphore简介 1.synchronized是java中的关键字,是用来控制线程同步的问题最常用的方法. 2.Semaphore是属于java的一个类,同样 ...

  8. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

  9. Java学习之线程通信(多线程(synchronized))--生产者消费者

    分析线程经典案例生产者消费者 /** 共享数据 */ class Resource { private String name; private int count=1; private boolea ...

随机推荐

  1. centos6.5 内核 :2.6.32 升级内核

    问题:    CentOS 6.5 的内核一般都是2.6,在2.6的内核下,Docker运行会比较卡,所以一般会选择升级到更高版本,本次教程升级版本为4.4.102 一.升级内核 1.查看内核版本 u ...

  2. Linux Shell 中 > 和 >> 的异同点和应用场景

    Linux Shell 中 > 和 >> 的异同点和应用场景 > 和 >> 的异同点 举例说明(start.sh 为某个服务的启动脚本,start.log 为某服务 ...

  3. Pytorch-索引与切片

    引言 本篇介绍Pytorch 的索引与切片 索引 1234567 In[3]: a = torch.rand(4,3,28,28)In[4]: a[0].shape # 理解上相当于取第一张图片Out ...

  4. C++学习笔记-static

    static做为关键字,在C++语言中运用在类中,代表着这个属性或者方法属于这个类 如果生成的对象修改了这个成员,那么其他对象共享修改后的值 定义和初始化 class ABC { public: in ...

  5. icon.css

    .icon-blank{ background:url('icons/blank.gif') no-repeat; } .icon-add{ background:url('icons/edit_ad ...

  6. 非常好的一个JS代码(RelativePosition.js)

    var RelativePosition = function(){ function getLeft( align, rect, rel ){ var iLeft = 0; switch (alig ...

  7. EditText inputType类型整理

    //文本类型,多为大写.小写和数字符号.     android:inputType="none"//输入普通字符    android:inputType="text& ...

  8. php调用shell的方法

    一.配置 查看php.ini中配置是否打开安全模式,主要是以下三个地方safe_mode =  (这个如果为off下面两个就不用管了)disable_functions = safe_mode_exe ...

  9. vim配置及插件安装笔记

    1. 首先打开vim的配置文件vimrc,并加入以下常用的配置: cd ~ mkdir .vim vim .vimrc " 设置当文件被改动时自动载入 set autoread " ...

  10. 什么是云服务器ECS

    云服务器(Elastic Compute Service,简称ECS)是阿里云提供的性能卓越.稳定可靠.弹性扩展的IaaS(Infrastructure as a Service)级别云计算服务.云服 ...