看这本书之前,对wait和notify认识大概就是,调用wait的线程A堵塞之后,一旦另外有线程调用notify方法。线程A会立马从wait方法处返回。看完这本书后。发现自己的认识实在太肤浅了。。。。。

线程调用wait()后,会释放已经获得的锁。

同一时候进入Waiting状态,而非Blocked状态。唯独等待其它的线程调用notify()方法且释放锁之后。当前线程才会从wait()方法处返回。只发出通知是不够用的。还须要发出通知的线程释放锁。

然而notify()方法的调用并不意味着锁的释放。

贴出原书的demo,稍作了些改动。

/**
*
*/
package chapter04; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit; /**
* 6-11
*/
public class WaitNotify {
private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
static boolean flag = true;
static Object lock = new Object(); public static void main(String[] args) {
Thread waitThread = new Thread(new Wait(), "WaitThread");
waitThread.start();
sleepSeconds(1); Thread notifyThread = new Thread(new Notify(), "NotifyThread");
notifyThread.start();
} static class Wait implements Runnable {
public void run() {
synchronized (lock) {
// 当条件不满足时,继续wait,同一时候释放了lock的锁
while (flag) {
try {
System.out.println(CuttentThreadName() + " flag is true. wait @ " + sdf.format(new Date()));
lock.wait();
System.out.println(CuttentThreadName() + " gained lock again. wait @ " + sdf.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 条件满足时。完毕工作
System.out.println(CuttentThreadName() + " flag is false. running @ " + sdf.format(new Date()));
}
}
} private static String CuttentThreadName() {
return Thread.currentThread().getName();
} static class Notify implements Runnable {
@Override
public void run() {
// 加锁,拥有lock的Monitor
synchronized (lock) {
// 获取lock的锁。然后进行通知,通知时不会释放lock的锁,
// 直到当前线程释放了lock后,WaitThread才干从wait方法中返回
System.out.println(CuttentThreadName() + " hold lock. notify @ " + sdf.format(new Date()));
lock.notifyAll();
flag = false;
sleepSeconds(5);
System.out.println(CuttentThreadName() + " is releasing lock @ " + sdf.format(new Date()));
}
// 再次加锁
synchronized (lock) {
System.out.println(CuttentThreadName() + " hold lock again. sleep @ " + sdf.format(new Date()));
sleepSeconds(5);
System.out.println(CuttentThreadName() + " is releasing lock @ " + sdf.format(new Date()));
}
}
} private static void sleepSeconds(int timeout) {
try {
TimeUnit.SECONDS.sleep(timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

输出结果为:

WaitThread flag is true. wait @ 20:58:32
NotifyThread hold lock. notify @ 20:58:33
NotifyThread is releasing lock @ 20:58:38
NotifyThread hold lock again. sleep @ 20:58:38
NotifyThread is releasing lock @ 20:58:43
WaitThread gained lock again. wait @ 20:58:43
WaitThread flag is false. running @ 20:58:43

通过输出结果,我们能够发现几个问题。

1.NotifyThread调用notifyAll()方法后,WaitThread并没有立马从wait()方法处返回。

由于这个时候NotifyThread并没有释放锁。

2.程序61行,NotifyThread第一次释放锁,然而WaitThread不争气,并没有抢到这把锁。依然处于Blocked状态。

3.直到67行。NotifyThread再一次释放锁。WaitThread获得了锁,这才从wait()处返回继续运行。

4.线程从wait()方法返回的前提是,获得synchronized须要的锁。

分析完原书的demo之后,是否有跟我一样的感觉,以前的认识是那么的too young too simple。

《Java并发编程的艺术》读书笔记:等待/通知机制的更多相关文章

  1. Java并发编程的艺术读书笔记(2)-并发编程模型

    title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...

  2. Java并发编程的艺术读书笔记(1)-并发编程的挑战

    title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...

  3. java并发编程实战《六》等待-通知机制

    用"等待-通知"机制优化循环等待 前言 在破坏占用且等待条件的时候,如果转出账本和转入账本不满足同时在文件架上这个条件,就用死循环的方式来循环等待. 1 // 一次性申请转出账户和 ...

  4. synchronized的实现原理-java并发编程的艺术读书笔记

    1.synchronized实现同步的基础 Java中的每个对象都是可以作为锁,具体有3种表现. 1.对于普通同步方法,锁是当前实例对象. 2.对于静态同步方法,锁是当前类的Class对象. 3.对于 ...

  5. 《Java并发编程实战》读书笔记一 -- 简介

    <Java并发编程实战>读书笔记一 -- 简介 并发的历史 并发的历史,也是人类利用有限的资源去提高生产效率的一个的例子. 设想现在有台计算机,这台计算机具有以下的资源: 单核CPU一个 ...

  6. 《Java并发编程的艺术》笔记

    第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种:无锁并发编程.CAS算法.使用最少线程.使 ...

  7. 《java并发编程实战》读书笔记2--对象的共享,可见性,安全发布,线程封闭,不变性

    这章的主要内容是:如何共享和发布对象,从而使它们能够安全地由多个线程同时访问. 内存的可见性 确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化. 上面的程序中NoVisibility可能 ...

  8. 《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

    不使用等待通知机制 实现线程间通信的 疑问分析 2018年04月03日 17:15:08       ayf 阅读数:33 编辑 <java多线程编程核心技术>一书第三章开头,有如下案例: ...

  9. 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式

    上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...

  10. 《Java并发编程实战》读书笔记

    Subsections 线程安全(Thread safety)锁(lock)共享对象对象组合基础构建模块任务执行取消和关闭线程池的使用性能与可伸缩性并发程序的测试显示锁原子变量和非阻塞同步机制 一.线 ...

随机推荐

  1. Linux命令之sort

    sort [选项] [文件] 对文本文件的行进行排序.常见的字符排序空字符串<数字<a<A<b<B...<z<Z (1).常用选项 -b,--ignore-l ...

  2. RHEL/CentOS网络相关的配置文件路径

    /etc/sysconfig/network-scripts/ifcfg-ens33 //IP地址,子网掩码等配置文件 /etc/sysconfig/network-scripts/ifcfg-lo ...

  3. Hive 默认分区

    在hive里面表可以创建成分区表,但是当分区字段的值是'' 或者 null时 hive会自动将分区命名为默认分区名称. 默认情况下,默认分区的名称为__HIVE_DEFAULT_PARTITION__ ...

  4. [Lydsy1806月赛] 质数拆分

    (mmp我已经不知道是第几次写NTT被卡了) 可以发现质数个数是 N/log(N) 级别的,1.5*10^5之内也只有 10000 多一点质数. 所以我们第一层暴力卷积,常数可以优化成 1/2. 然后 ...

  5. BZOJ 1430 小猴打架(prufer编码)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1430 [题目大意] 一开始森林里面有N只互不相识的小猴子,它们经常打架, 但打架的双方 ...

  6. 【枚举】【并查集】Gym - 101243F - Vitamins

    题意:有n片药,有三种颜色,白色比红色重,红色比蓝色重,给你一些它们之间的重量关系,比如1>3,2=4之类,问你它们的颜色,如果没法判断的输出?. 先并查集把等于号全缩起来,然后按照大于号建图, ...

  7. 【预处理】Codeforces Round #407 (Div. 2) C. Functions again

    考虑枚举每个子串开头的位置,然后答案转化成询问这个位置之后 哪个位置的前缀和 - 这位置的前缀和 最大(当然是已经把绝对值和正负的情况处理好了,可以发现按奇偶,这个序列只有两种情况),只需要预处理这两 ...

  8. django框架下celery+rabbitmq+flower完成异步任务

    [转载请注明出处:] http://www.cnblogs.com/yukityan/p/8035787.html 环境: ubuntu16.04 64位 安装: sudo apt-get insta ...

  9. [转]Servlet的load-on-startup

      在servlet的配置当中,<load-on-startup>5</load-on-startup>的含义是: 标记容器是否在启动的时候就加载这个servlet. 当值为0 ...

  10. iOS 在系统设置中展示Version, Build, Git等信息

     在设置中,展示自定义内容,如下图INFO区域内容:         步骤: 1.在项目中添加Settings.bundle文件 Root.plist和Root.plist的Source code如下 ...