synchronized wait notify 生产者消费者
1.生产者消费者模型
public class ProducterConsumerTest{
public static void main(String[] args){
System.out.println("this is a test...");
Message msg=new Message();
Producter pro=new Producter(msg);
Consumer con=new Consumer(msg);
new Thread(pro).start();
new Thread(con).start();
new Thread(con).start();
}
}
class Message {
String title;
String content;
public synchronized void set(String title,String content){
//问题1:while 还是 if
while (this.content!=null){
try{
this.wait();
}catch(Exception exc){}
}
//模拟延迟
try{
Thread.sleep(100);
}catch(Exception exc){}
this.title=title;
this.content=content;
System.out.println(Thread.currentThread().getName()+"-生产:"+this.title+this.content);
//问题2 notify 还是notifyAll
super.notify();
}
public synchronized void get(){
//问题1:while 还是 if
while(this.content==null){
try{
this.wait();
}catch(Exception exc){}
}
//模拟延迟
try{
Thread.sleep(100);
}catch(Exception exc){}
System.out.println(Thread.currentThread().getName()+"-消费:"+this.title+this.content);
this.title=null;
this.content=null;
//问题2 notify 还是notifyAll
super.notify();
}
}
class Producter implements Runnable {
Message msg;
public Producter(Message msg){
this.msg=msg;
}
@Override
public void run(){
for(int i=0;i<10;i++){
msg.set("华为"," Meate100");
}
}
}
class Consumer implements Runnable{
Message msg;
public Consumer(Message msg){
this.msg=msg;
}
@Override
public void run(){
for(int i=0;i<5;i++){
msg.get();
}
}
}
//运行结果(notifyAll()+while):
this is a test...
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
2.Entry Set(锁池)、Wait Set(等待池)
对于Entry Set:如果线程A已经持有了对象锁,此时有其他线程也想获得该对象锁的话,它只能进入Entry Set,并且线程处于BLOCKED状态。
对于Wait Set:如果线程A调用了wait()方法,那么线程A会释放该对象的锁,进入到Wait Set,并且线程处于WAITING状态。
3.Wait、Notify、NotifyAll 、Entry Set(锁池)、Wait Set(等待池)画图说明



4.衍生出的问题
A.用notify还是notifyAll:
线程1-生产
线程2-消费 -waiting
线程3-消费 -waiting
notify场景分析:
步骤一:线程1生产完成后wait(),执行notify()随机唤醒一个是线程2,判断之后满足条件,进行消费,线程2消费完后wait(),执行notify().
此时三个线程状态是
线程1-waiting
线程2-waiting-执行notify
线程3-waiting
步骤二:这是如果唤醒的是线程3,那么是不满足消费条件的,所以线程3继续wait(),而没有进行唤醒操作
这是问题产生了
线程1-waiting
线程2-waiting
线程3-waiting
死锁、死锁、死锁了...

如果我们用的是notifyAll(),那么步骤一线程2消费完成后,执行notifyAll(),结果是什么呢?
(1)如果是线程1抢到锁,满足条件,进行生产,生产完成后notifyAll()
(2)如果是线程3抢到锁,不满足条件,线程3wait(),释放锁,此时只有线程1是在锁池中,线程1会抢到锁,之后执行(1)
so,notify会导致死锁问题,最好使用notifyAll()
B.wait外层用while还是if:
notifyAll下if运行结果:

这里我没想明白,明明是同步方法为啥子会出现这个问题呢?
或者
就是当线程被wait之后进入等待队列,当被唤醒时,线程是继续往wait下面继续执行还是从synchronized monitor锁的地方再次执行?
答案只有一个:
上边的异常说明了->【wait被唤醒后,会继续往wait之后的代码执行而不是重新从monitor同步块处执行】 (这个结论是从代码运行推断,能力有限,没找到佐证,留待后续补充吧...........)
附上JDK中的说明

C.wait和synchronized绑定使用:
同上图
synchronized wait notify 生产者消费者的更多相关文章
- Java多线程之生产者消费者问题<一>:使用synchronized keyword解决生产者消费者问题
今天看了一片博文,讲Java多线程之线程的协作,当中作者用程序实例说明了生产者和消费者问题,但我及其它读者发现程序多跑几次还是会出现死锁,百度搜了下大都数的样例也都存在bug,经过细致研究发现当中的问 ...
- Java学习之线程通信(多线程(synchronized))--生产者消费者
分析线程经典案例生产者消费者 /** 共享数据 */ class Resource { private String name; private int count=1; private boolea ...
- Java多线程(九):生产者消费者模型
生产者消费者模型 生产者:生产任务的个体: 消费者:消费任务的个体: 缓冲区:是生产者和消费者之间的媒介,对生产者和消费者解耦. 当 缓冲区元素为满,生产者无法生产,消费者继续消费: 缓冲区元素为空, ...
- 生产者消费者问题--lock
# 代码: public class App { public static void main(String[] args) { Depot depot = new Depot(100); Prod ...
- 通过生产者消费者模式例子讲解Java基类方法wait、notify、notifyAll
wait(),notify()和notifyAll()都是Java基类java.lang.Object的方法. 通俗解释wait():在当前线程等待其它线程唤醒.notify(): 唤醒一个线程正在等 ...
- 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例
wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视.本文对这些关键字的使用进行了描述. 在 Java 中可以用 wait ...
- Java 学习笔记 使用synchronized实现生产者消费者模式
说明 Object.wait()使当前的线程进入到等待状态(进入到等待队列) Object.notifyAll() 唤醒等待中的全部线程 Object.notify() 随机唤醒一个线程 代码 con ...
- java使用synchronized与Semaphore解决生产者消费者问题对比
一.synchronized与信号量Semaphore简介 1.synchronized是java中的关键字,是用来控制线程同步的问题最常用的方法. 2.Semaphore是属于java的一个类,同样 ...
- java多线程15 :wait()和notify() 的生产者/消费者模式
什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...
随机推荐
- c++拷贝构造函数(翁恺c++公开课[26-27]学习笔记)
这节课在p26.拷贝构造中讲的很清楚,建议大家耐心的去看下. 什么时候会发生拷贝构造: 对象之间的初始化赋值 使用对象作为变量进行函数传参(通常使用引用来传参从而减去不必要的拷贝构造,提高效率和代码健 ...
- CentOS 7 启动流程
1.UEFI或BIOS初始化,运行POST开机自检 2.选择启动设备,Boot Sequence 系统启动次序一般含有:光驱.U盘.硬盘A.硬盘B.按次序查找各引导设备,第一个有引导程序的设备即为本次 ...
- 【PAT甲级】1014 Waiting in Line (30 分)(队列维护)
题面: 输入四个正整数N,M,K,Q(N<=20,M<=10,K,Q<=1000),N为银行窗口数量,M为黄线内最大人数,K为需要服务的人数,Q为查询次数.输入K个正整数,分别代表每 ...
- 【转】 android之如何在两个activity之间传递handler_利用broadcast广播机制
原文:http://blog.csdn.net/jason0539/article/details/18075293 这算是如何在两个activity之间传递handler的解决方案二了,解决方案一见 ...
- 树莓派4B踩坑指南 - (3)无显示器连接
无显示器连接 WiFi:如果是原装系统,直接修改wpa_supplicant.conf文件后,放入boot即可(一定注意ssid名称不要写错!!惨痛教训T^T) SSH:在boot盘下新建一个 SSH ...
- error C2664: “FILE *fopen(const char *,const char *)”: 无法将参数 1 从“LPCTSTR”转换为“const char *”
遇到这个问题,请打开本项目的Properties(属性)-------> Configuration Properties(配置属性)-------->General(常规)------- ...
- 手搓SSM
相关资料,网上的资料很多,但是文章看不懂,看别人写好的代码比较好理解 ssm-example mysssm 整个流程和原理 一个入口类,入口类需要在tomcat启动的时候执行 通过扫描文件加把文件取出 ...
- redis集群配置文件
bind xxx.xxx.xxx.xxx 绑定redis服务器网卡IP,默认为127.,即本地回环地址.这样的话,访问redis服务只能通过本机的客户端连接,而无法通过远程连接.如果bind选项为空的 ...
- Immediate Decodability[UVA644](Trie入门)
传送门 题意:给出一些数字串,判断是否有一个数字串是另一个串的前缀. 这题真的可以算是Trie树的一道模板题了. 先把Trie树建好,建树的时候记录一个sum表示一个节点有多少个串会包含此节点,然后再 ...
- vmware workstation导入ovf文件报错:未通过OVF规范一致性或虚拟硬件合规性检查
转自:https://blog.csdn.net/zs15yy/article/details/73793585 报错如下: 原因:这是因为OVF 版本不同导致的,VMware Workstation ...