多线程-生产者消费者(synchronized同步)
正解博客:https://blog.csdn.net/u011863767/article/details/59731447
永远在循环(loop)里调用 wait 和 notify,不是在 If 语句
现在你知道wait应该永远在被synchronized的背景下和那个被多线程共享的对象上调用,下一个一定要记住的问题就是,你应该永远在while循环,而不是if语句中调用wait。因为线程是在某些条件下等待的——在我们的例子里,即“如果缓冲区队列是满的话,那么生产者线程应该等待”,你可能直觉就会写一个if语句。但if语句存在一些微妙的小问题,导致即使条件没被满足,你的线程你也有可能被错误地唤醒。所以如果你不在线程被唤醒后再次使用while循环检查唤醒条件是否被满足,你的程序就有可能会出错——例如在缓冲区为满的时候生产者继续生成数据,或者缓冲区为空的时候消费者开始小号数据。所以记住,永远在while循环而不是if语句中使用wait!我会推荐阅读《Effective Java》,这是关于如何正确使用wait和notify的最好的参考资料。
有的这样说:(http://www.tuicool.com/articles/a6ram23)
因为在多核处理器环境中, Signal 唤醒操作可能会激活多于一个线程(阻塞在条件变量上的线程),使得多个调用等待的线程返回。所以用while循环对condition多次判断,可以避免这种假唤醒。
基于以上认知,下面这个是使用wait和notify函数的规范代码模板:
|
1
2
3
4
5
6
7
8
|
// The standard idiom for calling the wait method in Javasynchronized(sharedObject) { while(condition) { sharedObject.wait(); // (Releases lock, and reacquires on wakeup) } // do action based upon condition e.g. take or put into queue} |
就像我之前说的一样,在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。
注意:
1 永远在synchronized的方法或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。
2 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。
3 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。
生产者消费者代码:
https://zhuanlan.zhihu.com/p/20300609 代码有部分问题,修改如下
ProsumerToConsumer类
public class ProsumerToConsumer {
public static void main(String[] args) throws Exception {
Person person =new Person();
Thread t1=new Thread(new Producer(person),"生产者t1");
Thread t2=new Thread(new Producer(person),"生产者t2");
Thread t3=new Thread(new Producer(person),"生产者t3");
Thread s1=new Thread(new Consumer(person), "消费者s1");
Thread s2=new Thread(new Consumer(person), "消费者s2");
Thread s3=new Thread(new Consumer(person), "消费者s3");
s1.start();
s2.start();
Thread.sleep(2000);
t1.start();
t2.start();
t3.start();
}
}
producer代码:
public class Producer implements Runnable {
private Person person;
// private String name;
public Producer( Person person) {
this.person=person;
// this.name=name;
}
@Override
public void run() {
try {
person.producer();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
consumer代码:
public class Consumer implements Runnable{
private Person person;
public Consumer( Person person) {
this.person=person;
}
@Override
public void run() {
try {
person.consumer();
} catch (Exception e) {
e.printStackTrace();
}
}
}
person代码:
public class Person {
private static volatile int num=0;
private Object obj= new Object();
private static final int MAX_NUM=5;
public void producer()throws InterruptedException{
while(true){
synchronized (obj) {
while(num==MAX_NUM) {
System.out.println("box is full,size = " + num);
obj.wait();
}
num++;
System.out.println( Thread.currentThread().getName()+ num);
obj.notifyAll();
}
}
}
public void consumer() throws InterruptedException{
while (true) {
synchronized (obj) {
while (num==0) {
System.out.println("box is empty,size = " + num);
obj.wait();
}
num--;
obj.notifyAll();
System.out.println(Thread.currentThread().getName() + num);
}
}
}
}
实例验证1:如果判断用的是while 数据在队列容量范围之内。
while(num==MAX_NUM)
while(true){
synchronized (obj) {
while(num==MAX_NUM) {
System.out.println("box is full,size = " + num);
obj.wait();
}

实例验证2:如果判断用的是if ,数据已经超出了队列的容量
if(num==MAX_NUM)
while(true){
synchronized (obj) {
if(num==MAX_NUM) {
System.out.println("box is full,size = " + num);
obj.wait();
}

多线程-生产者消费者(synchronized同步)的更多相关文章
- java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】
java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...
- 使用Win32 API实现生产者消费者线程同步
使用win32 API创建线程,创建信号量用于线程的同步 创建信号量 语法例如以下 HANDLE semophore; semophore = CreateSemaphore(lpSemaphoreA ...
- Java实现多线程生产者消费者模式的两种方法
生产者消费者模式:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据.生产者生产一个,消费者消费一个,不断循环. 第一种实现方法,用BlockingQueue阻塞队 ...
- java实现多线程生产者消费者模式
1.概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消 ...
- java多线程 生产者消费者模式
package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...
- Java实现多线程生产者消费者模型及优化方案
生产者-消费者模型是进程间通信的重要内容之一.其原理十分简单,但自己用语言实现往往会出现很多的问题,下面我们用一系列代码来展现在编码中容易出现的问题以及最优解决方案. /* 单生产者.单消费者生产烤鸭 ...
- Python多线程-生产者消费者模型
用多线程和队列来实现生产者消费者模型 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threading imp ...
- [多线程] 生产者消费者模型的BOOST实现
说明 如果 使用过程中有BUG 一定要告诉我:在下面留言或者给我邮件(sawpara at 126 dot com) 使用boost::thread库来实现生产者消费者模型中的缓冲区! 仓库内最多可以 ...
- 操作系统实验 windows编程多线程 生产者消费者问题 画圆画方(内置bug版)
实验3:随便写的 #include <windows.h> #include <string> #include <stdio.h> #pragma warning ...
随机推荐
- Tensorflow 多层全连接神经网络
本节涉及: 身份证问题 单层网络的模型 多层全连接神经网络 激活函数 tanh 身份证问题新模型的代码实现 模型的优化 一.身份证问题 身份证号码是18位的数字[此处暂不考虑字母的情况],身份证倒数第 ...
- 5分钟学会maven入门
一.背景 1.定位:Maven是优秀的构建工具 2.意义:自动化构建,即节约了我们每天有相当一部分时间花在编 译.运行单元测试.生成文档.打包和部署等烦琐且不起眼的时间. 3.三要素:目标(Targe ...
- 关于Pytorch中accuracy和loss的计算
这几天关于accuracy和loss的计算有一些疑惑,原来是自己还没有弄清楚. 给出实例 def train(train_loader, model, criteon, optimizer, epoc ...
- VirtualBox下Centos6.8网络配置
win10环境下,VirtualBox和Centos6.8已经按照完毕,下面配置Centos6.8网络. 1.设置VirtualBox为桥接模式,具体的有三种联网方法,我们参考http://www.c ...
- [爬虫] requests库
requests库的7个常用方法 requests.request() 构造一个请求,支撑以下各种方法的基础方法 requests.get() 获取HTML网页的主要方法,对应于HTTP的GET re ...
- Oracle 用户管理权限
Oracle 用户管理权限 一.创建用户的Profile文件 SQL> create profile student limit // student为资源文件名 FAILED_LOGIN_AT ...
- P1004方格取数
这是提高组得一道动态规划题,也是学习y氏思考法的第一道题. 题意为给定一个矩阵,里面存有一些数,你从左上角开始走到右下角,另一个人从右下角开始走到左上角,使得两个人取数之和最大,当然一个数只可以取走一 ...
- CentOS7通过YUM安装NGINX稳定版本
创建 nginx.repo 文件 $ cd /etc/repos.d/ $ vim nginx.repo #写入以下内容 [nginx-stable] name=nginx stable repo b ...
- Codeforces 1194E. Count The Rectangles
传送门 看到 $n<=5000$,直接暴力枚举左右两条竖线 然后考虑怎么计算高度在某个范围内,左端点小于等于某个值,右端点大于等于某个值的横线数量 直接用权值树状数组维护当前高度在某个区间内的横 ...
- iview之tabs嵌套
iview之tabs嵌套 说明: iview组件中当嵌套使用 Tabs时,需要在Tabs中指定 name 属性来区分层级,然后在TabPane 中设置 tab 属性指向对应 Tabs 的 name 字 ...