快速掌握并发编程---线程阻塞与唤醒
时间:2022-07-28
本文章向大家介绍快速掌握并发编程---线程阻塞与唤醒,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
synchronized 结合 java.lang.Object
对象中的wait()
、notify()
、notifyAll()
。
应用
线程A
public class ThreadA extends Thread{
private Object lock;
public ThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock){
System.out.println("ThreadA---start");
try {
//实现线程阻塞
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadA---end");
}
}
}
线程B
public class ThreadB extends Thread {
private Object lock;
public ThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("ThreadB---start");
//实现线程的唤醒
lock.notify();
System.out.println("ThreadB---end");
}
}
}
测试
public class WaitDemo {
public static void main(String[] args) {
Object lock = new Object();
ThreadA threadA = new ThreadA(lock);
threadA.start();
ThreadB threadB = new ThreadB(lock);
threadB.start();
}
}
运行输出
ThreadA---start
ThreadB---start
ThreadB---end
ThreadA---end
ThreadA阻塞挂起,ThreadB唤醒,ThreadA被唤醒。
上面这段代码我们会发现被阻塞的线程什么时候被唤醒,取决于获得锁的线程什么时候执行完同步代码块并且释放锁。
那怎么做到显示控制呢?我们就需要借 助 一 个 信 号机 制 :在 Object 对 象 中 ,提 供 了wait/notify/notifyall,可以用于控制线程的状态
wait/notify/notifyAll 基本概念
- wait:表示持有对象锁的线程 A 准备释放对象锁权限,释放
CPU
资源并进入等待状态。 - notify:表示持有对象锁的线程 A 准备释放对象锁权限,通知
JVM
唤醒某个竞争该对象锁的线程 X。线程 A 同步代码块执行结束并且释放了锁之后,线程 X 直接获得对象锁权限,其他竞争线程继续等待(即使线程 X 同步完毕,释放对象锁,其他竞争线程仍然等待,直至有新的 notify ,notifyAll 被调用)。 - notifyAll:notifyall 和 notify 的区别在于,notifyAll 会唤醒所有竞争同一个对象锁的所有线程,当已经获得锁的线程A 释放锁之后,所有被唤醒的线程都有可能获得对象锁权限(notifyAll唤醒等待队列中所有线程,然后所有被唤醒的线程重新进入锁竞争)。
需要注意的是:
三个方法都必须在 synchronized 同步关键字所限定的作用域中调用 ,否则会报错
java.lang.IllegalMonitorStateException
意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。另外,通过同步机制来确保线程从 wait 方法返回时能够感知到感知到 notify 线程对变量做出的修改waity /notify 。
waity /notify 的基本原理
注意两个队列:
- 等待队列:notifyAll/notify唤醒的就是等待队列中的线程;
- 同步线程:就是竞争锁的所有线程,等待队列中的线程被唤醒后进入同步队列。
sleep与wait的区别
sleep
- 让当前线程休眠指定时间。
- 休眠时间的准确性依赖于系统时钟和CPU调度机制。
- 不释放已获取的锁资源,如果sleep方法在同步上下文中调用,那么其他线程是无法进入到当前同步块或者同步方法中的。
- 可通过调用interrupt()方法来唤醒休眠线程。
- sleep是Thread里的方法
wait
- 让当前线程进入等待状态,当别的其他线程调用notify()或者notifyAll()方法时,当前线程进入就绪状态
- wait方法必须在同步上下文中调用,例如:同步方法块或者同步方法中,这也就意味着如果你想要调用wait方法,前提是必须获取对象上的锁资源
- 当wait方法调用时,当前线程将会释放已获取的对象锁资源,并进入等待队列,其他线程就可以尝试获取对象上的锁资源。
- wait是Object中的方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 纲手推荐程序笔记1-p5.js创意游戏编程
- 由浅入深彻底了解 Python 闭包和装饰器
- leetcode1078 Occurrences After Bigram
- 负二进制加法实现
- 如何在O(1)时间复杂度下实现LRU
- 字符串拼接的N种方式
- MySQL 解决查询NULL的问题
- 矩阵旋转的解决
- Python partial最通俗的理解
- Django Form的使用
- Python每日一题:装饰器(完整篇)
- Vue视图渲染原理解析,从构建VNode到生成真实节点树
- Vue你不得不知道的异步更新机制和nextTick原理
- 手摸手带你理解Vue的Watch原理
- rollup环境搭建(es6转es5、压缩、本地服务器、热更新)