wait和notify

多线程是需要同步协作,比如QuartzSchedulerThread,作为Quartz的任务调度线程,如果设置该线程暂停,那么这个线程就必须wait, 等外界通知继续的时候,再执行任务。

// check if we're supposed to pause...

synchronized (sigLock) {

while (paused && !halted.get()) {

try {

// wait until togglePause(false) is called...

//使当前线程暂停1秒

sigLock.wait(1000L);

} catch (InterruptedException ignore) {

}

}

if (halted.get()) {

break;

}

}

如果要调用对象的wait方法,就必须先获得这个对象的锁–>synchronized (sigLock)。

当线程执行了wait后,就释放了锁,这样当线程在wait期间,QuartzScheduler就有机会获得锁。然后就可以执行唤醒操作notify。

如果多个线程都在wait sigLock, 当调用 notify的时候只能唤醒其中一个线程(由JVM决定),调用notifyAll则能唤醒全部线程。

从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。

相应的notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。

QuartzScheduler执行start方法,会调用schedThread.togglePause(false); 取消QuartzSchedulerThread的暂停,初始化的时候QuartzSchedulerThread的pause是true

void togglePause(boolean pause) {

synchronized (sigLock) {

paused = pause;

if (paused) {

signalSchedulingChange(0);

} else {

sigLock.notifyAll();

}

}

}

sleep 和 wait 的区别

Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

经典的ABC打印问题

建立三个线程,A线程打印10次A,B线程打印10次B, C线程打印10次C,要求线程同时运行,交替打印10次ABC。

public class MyThreadPrinter2 implements Runnable {

private String name;

private Object prev;

private Object self;

private MyThreadPrinter2(String name, Object prev, Object self) {

this.name = name;

this.prev = prev;

this.self = self;

}

@Override

public void run() {

int count = 10;

while (count > 0) {

synchronized (prev) {

synchronized (self) {

System.out.print(name);

count--;

self.notify();

}

try {

prev.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) throws Exception {

Object a = new Object();

Object b = new Object();

Object c = new Object();

MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);

MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);

MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);

new Thread(pa).start();

new Thread(pb).start();

new Thread(pc).start(); }

}

A—>B—>C—>A

要想控制线程执行的顺序,就需要使用锁机制,每个线程都持有自己的锁,并且在自己上一个线程的锁释放的时候才能执行。

比如B执行的条件:

1. A 锁释放

2. 获得自己的B 锁

A执行的条件:

1. C锁释放

2. 获得自己的A 锁

执行流程:

1. 获得前一个线程的锁 synchronized (prev)

2. 获得自己的锁,执行方法,释放自己的锁,通知下一个线程 synchronized (self) { self.notify(); }

3. 释放前一个线程的锁,继续监听锁,prev.wait();

总结:

wait就是监听锁对象,将当前线程放入锁的等待队列中。

notify就是通知监听线程,告诉监听该锁的线程,你们可以获得锁了。

notify只会让其中一个监听线程执行,由JVM决定。notifyAll会通知所有的监听线程。

那么问题来了!

如果A 执行了System.out.print(name);方法后,CPU又切换到了主线程。启动了B 和C 线程,

B 获取不到A锁,继续等待。C 获得了B锁,然后准备获得自己的C锁,这时A居然执行完成了,释放了C锁,所以C就可以执行方法了。 然后就是落后的B,先获得A锁,再获得B锁,执行。

就成了ACBACB…..

模拟代码:

public void run() {

int count = 10;

while (count > 0) {

synchronized (prev) {

synchronized (self) {

System.out.print(name);

count--;

try{

//先睡会,CPU你去找其他线程

Thread.sleep(1);

}

catch (InterruptedException e){

e.printStackTrace();

}

self.notify();

}

try {

prev.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

解决:

public class MyThreadPrinter2 implements Runnable {

private String name;

private Object prev;

private Object self;

private MyThreadPrinter2(String name, Object prev, Object self) {

this.name = name;

this.prev = prev;

this.self = self;

}

@Override

public void run() {

int count = 10;

while (count > 0) {

synchronized (prev) {

synchronized (self) {

System.out.print(name);

count--;

try{

Thread.sleep(1);

}

catch (InterruptedException e){

e.printStackTrace();

}

self.notify();

}

try {

prev.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) throws Exception {

Object a = new Object();

Object b = new Object();

Object c = new Object();

MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);

MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);

MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);

new Thread(pa).start();

//使主线程睡眠,这样CPU就不会在A执行结束前去执行B或者C,给A足够的时间完成调度。

Thread.sleep(10);

//主线程睡眠之间到了时候,恢复CPU调度,启动线程B

new Thread(pb).start();

Thread.sleep(10);

new Thread(pc).start();

Thread.sleep(10);

}

}

synchronized的4种用法

1.方法声明

public synchronized void synMethod() {

//方法体

}

一次只能一个线程进入该方法。

2.对某一代码块使用

public int synMethod(int a1){

synchronized(a1) {

//一次只能有一个线程进入

}

}

文章来自

java线程没wait前调用notify,深入Java线程 之 wait和notify相关推荐

  1. java rtmp_搭建rtmp直播流服务之2:使用java实现ffmpeg命令接口化调用(用java执行ffmpeg命令)...

    一.环境搭建 1.安装ffmpeg 下载对应系统的ffmpeg安装包,个人采用windows平台进行开发,所以安装了windows版本(各平台ffmpeg命令都是一样的,无须纠结) 2.ffmpeg的 ...

  2. idea 新建的java项目没发run_IntelliJ IDEA创建普通的Java 项目及创建 Java 文件并运行的教程...

    最近突然看到这篇几年前随手记录的文章,居然浏览量那么高.看来很多小伙伴也开始从 Eclipse 转到 IDEA,这里为了让大家更好的掌握 IDEA 的使用,我建议大家可以看看下面这个 IDEA 教程. ...

  3. java多线程实战指南_学习笔记《Java多线程编程实战指南》二

    2.1线程属性 属性 属性类型及用途 只读属性 注意事项 编号(id) long型,标识不同线程 是 不适合用作唯一标识 名称(name) String型,区分不同线程 否 设置名称有助于代码调试和问 ...

  4. 线程中这么调用类_这些线程知识总结是真的到位!java开发两年的我看的目瞪口呆

    前言 什么是线程:程序中负责执行的那个东东就叫做线程(执行路线,进程内部的执行序列),或着说是进程的子任务. Java中实现多线程有几种方法 继承Thread类: 实现Runnable接口: 实现Ca ...

  5. 线程类中如何调用service_你真的了解Java多线程吗?

    一.程序.进程和线程.单核CPU和多核CPU.并行与并发 什么是程序? 程序是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码. 什么是进程? 进程是指程序的一次执行过程,或是正在运 ...

  6. Java线程面试的前50个问题,面向初学者和经验丰富的程序员

    您可以参加任何Java面试,无论是大四还是中级,经验或新来的人,一定会看到线​​程,并发和多线程中的几个问题. 实际上,这种内置的并发支持是Java编程语言的最强优势之一,并帮助它在企业界和程序员中同 ...

  7. 线程组多次调用_详细分析 Java 中启动线程的正确和错误方式

    start 方法和 run 方法的比较 代码演示: /** *  * start() 和 run() 的比较  *  *  * @author 踏雪彡寻梅  * @version 1.0  * @da ...

  8. 【Java 线程的深入研究3】最简单实例说明wait、notify、notifyAll的使用方法

    wait().notify().notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法.随着jvm运行平台的不同可能有些 ...

  9. Java 编程问题:十、并发-线程池、可调用对象和同步器

    原文:Java Coding Problems 协议:CC BY-NC-SA 4.0 贡献者:飞龙 本文来自[ApacheCN Java 译文集],自豪地采用谷歌翻译. 本章包括涉及 Java 并发的 ...

最新文章

  1. python flask表单语法_Flask框架如何使用表单
  2. 教你打造 Android 中的 IOC 框架
  3. VTK:可视化之CurvedReformation
  4. nginx 禁止通过IP,未绑定域名访问服务器
  5. 【学神】1-4 用户及用户组管理
  6. 透视宝移动端对Unity手机游戏引擎监控实现
  7. 工具使用-----Jmeter教程 简单的压力测试
  8. c语言for嵌套循环语句,关于for嵌套循环语句的疑问
  9. 最新!全球学术排名出炉:21 所中国大学位居世界 100 强
  10. 《Android群英传》— Android 书籍
  11. BZOJ 1106: [POI2007]立方体大作战tet 树状数组 + 贪心
  12. android image 位移动画_Android共享元素转场动画实现
  13. 图像处理(一)图像灰度化的三种方式
  14. linux下geos如何编译,geos库交叉编译生成ARM平台库
  15. python竖线_Matplotlib示例.43 横线与竖线
  16. 元数据是什么?如何管理元数据?
  17. 设置input框只能输入数字或者只能输入英文
  18. 2022年金属非金属矿井通风上岗证题库及模拟考试
  19. 搜索引擎:高级搜索技巧(初)
  20. 12V铅酸电池充放电保护板

热门文章

  1. C# 倍福ADS带数组成员的结构体数组通信
  2. 宗宁:不死京东的收官之战--附刘强东点评
  3. 大数据分析PyTorchx深度学习框架教程
  4. iOS6以上屏幕旋转详解
  5. 电脑上的小白系统没内存怎么办?
  6. 【单片机毕业设计】【mcuclub-jj-019】基于单片机的油烟机的设计
  7. 计算机最快键操作方法,电脑快捷键技巧
  8. Windows 删除文件命令
  9. linux的可执行文件存放位置
  10. Python:不同进制的转换整理