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,也就是切换到另一个线程. 为了实 ...
随机推荐
- 安装httpd过程,将网站部署到httpd过程
1,配置DNSvi /etc/resolv.conf 加入以下代码 nameserver 192.168.0.1 nameserver 8.8.8.8 nameserver 8.8.4.4 2.输入y ...
- Kibana加载样本数据
kibana 6.2 加载样本数据 kibana loading sample data 下载样本数据 # 莎士比亚经典作品 wget https://download.elastic.co/demo ...
- Struts2(接受表单参数)请求数据自动封装和数据类型转换
Struts2请求数据自动封装: (1)实现原理:参数拦截器 (2)方式1:jsp表单数据填充到action中的属性: 普通的成员变量,必须给set,get可以不给的. 注意点,A ...
- day8--socket网络编程进阶
socket:socket就是实现服务器和客户端数据的交换,服务器端接收并发送数据,客户端发送并接收数据,并且需要注意的是,在python3中,socket值接收字节.因为客户端在发送连接给服务器的时 ...
- 【AtCoder】AGC017
在此处输入标题 标签(空格分隔): 未分类 A - Biscuits dp[i][0/1]表示当前和是偶数还是奇数,直接转移即可 #include <bits/stdc++.h> #def ...
- linux命令简写解释
命令缩写: ls:list(列出目录内容) cd:Change Directory(改变目录) su:switch user 切换用户rpm:redhat package manager 红帽子打包管 ...
- Kubernetes学习系列
这段时间项目组内想要引入Kubernetes,作为第二代容器调度引擎,故最近在系统的学习Kubernetes.整理了一些学习笔记,心得,放到博客中,一来记录自己的学习经过,二来看能否帮到有需要的同学. ...
- 第八章| 3. MyAQL数据库|Navicat工具与pymysql模块 | 内置功能 | 索引原理
1.Navicat工具与pymysql模块 在生产环境中操作MySQL数据库还是推荐使用命令行工具mysql,但在我们自己开发测试时,可以使用可视化工具Navicat,以图形界面的形式操作MySQL数 ...
- Spring框架学习08——自动代理方式实现AOP
在传统的基于代理类的AOP实现中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大.解决方案:自动创 ...
- git小白入门全攻略
git是什么(写在前边的叨叨,就是给一点不懂的小白打个比喻,大佬请自行跳过) git在平时的开发中用的太频繁了,以至于我都不知道如何去形容它.囧. 假设我们开发的工作类似于图书整理,写的代码就是很多人 ...