Java并发编程系列之三十二:丢失的信号
这里的丢失的信号是指线程必须等待一个已经为真的条件,在開始等待之前没有检查等待条件。这样的场景事实上挺好理解,假设一边烧水,一边看电视,那么在水烧开的时候。由于太投入而没有注意到水被烧开。
丢失的信号指的就是这样的情况。
创建两个线程分别运行通知和等待方法,而且将运行通知的线程先与运行等待的线程,以下的代码演示了这点:
package com.rhwayfun.patchwork.concurrency.r0414;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Created by rhwayfun on 16-4-14.
*/
public class MissedNotifyDemo {
//持有的锁
private static Object lock = new Object();
//日期格式器
private static final DateFormat format = new SimpleDateFormat("HH:mm:ss");
//等待线程运行的方法
public void waitMethod() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + ": enter waitMethod at "
+ format.format(new Date()));
synchronized (lock){
//调用wait方法运行等待
System.out.println(Thread.currentThread().getName() + ": start invoke wait method at "
+ format.format(new Date()));
lock.wait();
System.out.println(Thread.currentThread().getName() + ": end invoke wait method at "
+ format.format(new Date()));
}
System.out.println(Thread.currentThread().getName() + ": exit waitMethod at "
+ format.format(new Date()));
}
//通知线程运行的方法
public void notifyMethod(){
System.out.println(Thread.currentThread().getName() + ": exit notifyMethod at "
+ format.format(new Date()));
synchronized (lock){
//调用通知的方法
System.out.println(Thread.currentThread().getName() + ": start invoke notify method at "
+ format.format(new Date()));
lock.notifyAll();
System.out.println(Thread.currentThread().getName() + ": end invoke notify method at "
+ format.format(new Date()));
}
System.out.println(Thread.currentThread().getName() + ": exit notifyMethod at "
+ format.format(new Date()));
}
static class WaitThread implements Runnable{
private MissedNotifyDemo missedNotifyDemo;
public WaitThread(MissedNotifyDemo missedNotifyDemo) {
this.missedNotifyDemo = missedNotifyDemo;
}
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(1000);
missedNotifyDemo.waitMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class NotifyThread implements Runnable{
private MissedNotifyDemo missedNotifyDemo;
public NotifyThread(MissedNotifyDemo missedNotifyDemo) {
this.missedNotifyDemo = missedNotifyDemo;
}
@Override
public void run() {
try {
//休眠的时间必须要小于等待线程的休眠时间
TimeUnit.MILLISECONDS.sleep(500);
missedNotifyDemo.notifyMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args){
MissedNotifyDemo missedNotifyDemo = new MissedNotifyDemo();
new Thread(new WaitThread(missedNotifyDemo),"WaitThread").start();
new Thread(new NotifyThread(missedNotifyDemo),"NotifyThread").start();
}
}
运行结果例如以下:
WaitThread由于丢失了来自NotifyThread的通知而一直陷入等待中。当然,这里仅仅是演示了这样的情况。在实际的样例中,运行等待的线程都须要一个等待条件。为了避免出现丢失的信号。仍然须要对条件变量进行while循环的推断。
关于等待通知机制的补充
- 每当在等待一个条件时。一定要确保在条件变量变为真的时候才发出唤醒的通知
- 在调用wait/notify/notifyAll方法时。必须首先获得锁
- 每次调用完wait方法,获得锁就会自己主动释放
- 调用notify时,JVM从等待队列中的一个线程进行唤醒,调用notifyAll时,将等待队列中全部线程都唤醒
- 仅仅有同一时候满足两个条件时才干使用notify:一是全部等待线程的类型都同样,这就是说,等待队列仅仅与一个条件变量相关,而且全部的线程在唤醒后运行的都是同样的操作;二是单进单出,也就是说在条件变量的每一个通知,要求仅仅能最多唤醒一个线程
Java并发编程系列之三十二:丢失的信号的更多相关文章
- java并发编程JUC第十二篇:AtomicInteger原子整型
AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作.AtomicInteger 作为java.util.concurrent.atomic包的一部分,从Java 1 ...
- Java并发编程的艺术(十二)——并发容器和框架
ConcurrentHashMap 为什么需要ConcurrentHashMap HashMap线程不安全,因为HashMap的Entry是以链表的形式存储的,如果多线程操作可能会形成环,那样就会死循 ...
- 转:【Java并发编程】之十二:线程间通信中notifyAll造成的早期通知问题(含代码)
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17229601 如果线程在等待时接到通知,但线程等待的条件还不满足,此时,线程接到的就是早期 ...
- Java并发编程的艺术(十二)——线程安全
1. 什么是『线程安全』? 如果一个对象构造完成后,调用者无需额外的操作,就可以在多线程环境下随意地使用,并且不发生错误,那么这个对象就是线程安全的. 2. 线程安全的几种程度 线程安全性的前提:对『 ...
- 【Java并发编程】之十二:线程间通信中notifyAll造成的早期通知问题
如果线程在等待时接到通知,但线程等待的条件还不满足,此时,线程接到的就是早期通知,如果条件满足的时间很短,但很快又改变了,而变得不再满足,这时也将发生早期通知.这种现象听起来很奇怪,下面通过一个示例程 ...
- 干货:Java并发编程系列之volatile(二)
接上一篇<Java并发编程系列之synchronized(一)>,这是第二篇,说的是关于并发编程的volatile元素. Java语言规范第三版中对volatile的定义如下:Java编程 ...
- Java并发编程系列-(5) Java并发容器
5 并发容器 5.1 Hashtable.HashMap.TreeMap.HashSet.LinkedHashMap 在介绍并发容器之前,先分析下普通的容器,以及相应的实现,方便后续的对比. Hash ...
- Java并发编程系列-(4) 显式锁与AQS
4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...
- Java并发编程系列-(3) 原子操作与CAS
3. 原子操作与CAS 3.1 原子操作 所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何context switch,也就是切换到另一个线程. 为了实 ...
随机推荐
- C# 读取WAV文件(详细)
class WAVReader { #region RIFF WAVE Chunk private string Id; //文件标识 private double Size; //文件大小 priv ...
- 彻底解决:java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for column 'name' at row 1
转载:https://blog.csdn.net/qq_31122833/article/details/83992085
- poj2391
链接:http://poj.org/problem?id=2391 题解: 二分答案,变成判定性问题,只需把能经过的边在当前图中联通 另外对牛和牛棚要拆点 代码: #include <cstdi ...
- Python字符串相加以及字符串格式化
1.在Python中字符串a占用一块内存地址,字符串b也占用一块内存地址,当字符串a+b时,又会在内存空间中开辟一块新的地址用来存放a+b. a 地址一 b 地址二 a+b 地址三 因此内存中就占了三 ...
- BZOJ1051 [HAOI2006]受欢迎的牛 Tarjan 强连通缩点
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1051 题意概括 有n只牛,有m个羡慕关系. 羡慕关系具有传递性. 如果A羡慕B,B羡慕C,那么我们 ...
- Topic路由模式
原本理解的不够彻底,程序总是不太对.所以查询了资料,关于这种模式的意思做了仔细的解读,复制的文字. 一:介绍 1.模式 2.知识点 其中,#可以匹配一个或者多个字符 其中,*可以匹配一个字符 3.仔细 ...
- java中与和或的注意点
1.&&和&的区别 &:无论左边是true是false.右边都运算. &&:当左边为false时,右边不运算. 2.|与||的区别 |:两边都参与运算. ...
- Linux —— 常见指令及其英文全称
alias:给命令起别名 awk = "Aho Weiberger and Kernighan" ,三个作者的姓的第一个字母 bash:GNU Bourne-Again Shell ...
- Jmeter脚本录制方法(二)手工编写脚本(jmeter与fiddler结合使用)
jmeter脚本录制方法可以分三种,前几天写的一篇文章中,已介绍了前两种,今天来说下第三种,手工编写脚本,建议使用这一种方法,虽然写的过程有点繁琐,但调试脚本比前两者方式都要便捷. 首先来看下三种方式 ...
- php反序列化简叙
0x01 php简单的反序列化 这题是在网上看到的,原题连接不太了解,但是源码题目给了出来,稍微下文件名和排版在本地测试 <?php class SoFun{ protected $file=' ...