这里的丢失的信号是指线程必须等待一个已经为真的条件,在開始等待之前没有检查等待条件。这样的场景事实上挺好理解,假设一边烧水,一边看电视,那么在水烧开的时候。由于太投入而没有注意到水被烧开。

丢失的信号指的就是这样的情况。

创建两个线程分别运行通知和等待方法,而且将运行通知的线程先与运行等待的线程,以下的代码演示了这点:

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循环的推断。

关于等待通知机制的补充

  1. 每当在等待一个条件时。一定要确保在条件变量变为真的时候才发出唤醒的通知
  2. 在调用wait/notify/notifyAll方法时。必须首先获得锁
  3. 每次调用完wait方法,获得锁就会自己主动释放
  4. 调用notify时,JVM从等待队列中的一个线程进行唤醒,调用notifyAll时,将等待队列中全部线程都唤醒
  5. 仅仅有同一时候满足两个条件时才干使用notify:一是全部等待线程的类型都同样,这就是说,等待队列仅仅与一个条件变量相关,而且全部的线程在唤醒后运行的都是同样的操作;二是单进单出,也就是说在条件变量的每一个通知,要求仅仅能最多唤醒一个线程

Java并发编程系列之三十二:丢失的信号的更多相关文章

  1. java并发编程JUC第十二篇:AtomicInteger原子整型

    AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作.AtomicInteger 作为java.util.concurrent.atomic包的一部分,从Java 1 ...

  2. Java并发编程的艺术(十二)——并发容器和框架

    ConcurrentHashMap 为什么需要ConcurrentHashMap HashMap线程不安全,因为HashMap的Entry是以链表的形式存储的,如果多线程操作可能会形成环,那样就会死循 ...

  3. 转:【Java并发编程】之十二:线程间通信中notifyAll造成的早期通知问题(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17229601 如果线程在等待时接到通知,但线程等待的条件还不满足,此时,线程接到的就是早期 ...

  4. Java并发编程的艺术(十二)——线程安全

    1. 什么是『线程安全』? 如果一个对象构造完成后,调用者无需额外的操作,就可以在多线程环境下随意地使用,并且不发生错误,那么这个对象就是线程安全的. 2. 线程安全的几种程度 线程安全性的前提:对『 ...

  5. 【Java并发编程】之十二:线程间通信中notifyAll造成的早期通知问题

    如果线程在等待时接到通知,但线程等待的条件还不满足,此时,线程接到的就是早期通知,如果条件满足的时间很短,但很快又改变了,而变得不再满足,这时也将发生早期通知.这种现象听起来很奇怪,下面通过一个示例程 ...

  6. 干货:Java并发编程系列之volatile(二)

    接上一篇<Java并发编程系列之synchronized(一)>,这是第二篇,说的是关于并发编程的volatile元素. Java语言规范第三版中对volatile的定义如下:Java编程 ...

  7. Java并发编程系列-(5) Java并发容器

    5 并发容器 5.1 Hashtable.HashMap.TreeMap.HashSet.LinkedHashMap 在介绍并发容器之前,先分析下普通的容器,以及相应的实现,方便后续的对比. Hash ...

  8. Java并发编程系列-(4) 显式锁与AQS

    4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...

  9. Java并发编程系列-(3) 原子操作与CAS

    3. 原子操作与CAS 3.1 原子操作 所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何context switch,也就是切换到另一个线程. 为了实 ...

随机推荐

  1. ef 数据库连接字符串加密

    public testContext() : base(GetConnection(), true) { } public static DbConnection GetConnection() { ...

  2. 在.NET环境下使用KAFKA

    近日基于项目的解耦与削峰需求,决定在项目中引入消息队列.因为同时项目部分业务已经迁移到Java上,所以消息队列组件又要兼顾Java环境下的使用,选来选去对比了RabbitMQ.RocketMQ和Kaf ...

  3. python算法双指针问题:二分查找

    这里要注意的是//向下取整,下次循环时,如果大于查找的数字,start+1. 并且,只能向下取整,如果向上取整. 那么,在比较第一个数时,start = 0 .end = 1.mid = 1.就会进入 ...

  4. JAVA开发工程师面试(1)

    我已经有很长一段时间没有更新博客了,难道是博主我变懒惰了吗?哎,这样可不行啊,我还有好多知识要学习,要和大家分享.以后我需要更加努力,改掉自己的惰性.本人文采不怎么样,只能是把自己所想的说出来,想和大 ...

  5. linux命令之grep用法

    grep是linux中很常用的一个命令,主要功能就是进行字符串数据的对比,能使用正则表达式搜索文本,并将符合用户需求的字符串打印出来.grep全称是Global Regular Expression ...

  6. Python 可命名元祖

    import collections MytupleClass = collections.namedtuple('MytupleClass',['x','y','z']) obj = Mytuple ...

  7. Python replace

    一.replace替换 a = "wohaoshuai" a.replace('a','o') wohooshuoi a.replace('a','') wohoshui

  8. BZOJ1042 [HAOI2008]硬币购物 完全背包 容斥原理

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1042 题目概括 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了t ...

  9. Java 处理 iphone拍照后 图片EXIF属性翻转90度的方法

    http://blog.csdn.net/z69183787/article/details/50320821 Java获取照片EXIF信息 http://blog.csdn.net/ghsau/ar ...

  10. request中获取post的json对象数据content-type=“text/plain”

    其实采用http://www.cnblogs.com/SimonHu1993/p/7295750.html中的方法一都能获取到,就是通过获取request中的流数据,拿到json数据,理论上应该适用各 ...