Java多线程中sleep()、wait()、yield()、notify()、notifyAll()理论知识
🔗参考链接:
https://www.cnblogs.com/aspirant/p/8876670.html
https://www.pianshen.com/article/42791090981/
必须明白的前置知识点:
线程所具有的资源主要有两个部分: 【CPU资源】和【锁资源】
- CPU资源: CPU资源被划分成时间片,一旦一个线程获得时间片就有权力执行自己的代码块
- 锁资源: 一但一个线程掌握一个对象的锁其他线程无法对该对象进行存取
sleep(): 让出CPU资源但保存锁资源
wait(): 让出CPU资源和锁资源
下面这张图非常重要,一旦能够默写出来在思维上能够与后续Java多线程的学习起到前呼后应的效果
线程状态
状态名称 | 状态描述 |
---|---|
新建状态(new) | 当线程对象创建后即进入了新建状态,eg: Thread t = new MyThread(); |
就绪状态(runnable) | 当调用线程对象的start()方法(t.start()),线程就进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好运行的准备,一旦获得CPU的时间片就进入运行状态。 |
运行状态(running) | 可运行状态(runnable)的线程获得CPU时间片后就立即进入运行状态(就绪状态是运行状态的唯一接口)。 |
阻塞状态(blocked) | 处于运行状态的线程由于某种原因而暂时放弃CPU使用权后的状态.(阻塞状态分为三种:等待阻塞、同步阻塞、其他阻塞) |
死亡状态(dead) | 线程执行任务完毕或在运行过程中出现不可修复的错误 |
阻塞状态的三种类型
- 【等待阻塞】:运行状态中的线程执行wait()方法,释放CPU资源保留锁资源从而进入等待阻塞状态。JVM会将等待阻塞状态的线程放入等待队列(waiting sequence)中。
- 【同步阻塞】:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,获取synchronized同步锁失败,它会进入同步阻塞状态,则JVM会把该线程放入锁池(lock pool)中
- 【其他阻塞】:通过调用sleep()或join()或发出I/O请求超时会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
1. sleep() - 让正在运行的线程进入其他阻塞状态
sleep会让线程释放CPU资源但保存锁资源,提供其他线程运行的机会且不用考虑优先级,
可以通过调用interrupt()方法来唤醒休眠的线程。
2. yield() - 让正在运行的线程再次回到就绪状态(有限等待)
yield()方法释放出CPU资源只提供给同优先级的线程
(yield()方法只有一个目的: 就是告诉线程调度器自身的工作已经完成差不多了,可以让别的具有相同级别的线程过了抢占CPU资源完成工作)
3. wait(): - 让正在运行的线程进入等待阻塞状态
处于等待阻塞状态的线程会通过JVM调用进入等待序列中待notify\notifyAll()来唤醒调入锁标志池中
4. join(): - 让正在运行的线程进入其他阻塞状态(让权等待)
在实际操作中一个线程调用另一个线程的join()方法让出CPU资源进入其他阻塞状态等到让给的线程完成工作之后进入就绪状态
wait()、notify()、notifyAll的工作机制
wait()、notify()、notifyAll()都是Object类中的方法 - 他们是用来协调多个线程对共享数据的存取,所以必须出现在synchronized快中
synchrnoized关键字是用来保护共享数据,防止其他线程对共享数据的存取。但是为了保证共享资源具有一定的并发能力
让其他线程有一定机会进行操作则需要调用wait()、notify()、notifyAll()这三个方法进行灵活控制。
(1)一个运行态的线程调用wait()方法进入等待阻塞状态让出CPU和锁资源进入等待序列中,此时其他线程可以进入synchronized块中
(2)当调用notify()方法,将从等待序列中调用任意一个线程进入锁标志池中,只有锁标志池中的线程才能获得对象的锁标志。
(3)当调用notifyAll()方法,将从等待序列中调用所有的线程进入锁标志池中。
3. Java中wait()、sleep()的区别?
1. 【所属的类不同】wait()属于Object类的方法,sleep()属于Thread类的方法。
2. 【CPU资源和锁资源释放不同】wait()方法释放CPU和锁资源,sleep()方法仅释放CPU资源但保存锁资源。
3. 【各类的工作机制不同】
一个运行态线程调用wait()方法进入等待阻塞状态被放入等待序列等待notify/notifyAll唤醒进入锁标志池中(用于锁机制)。
一个运行态线程调用sleep()方法进入其他阻塞状态一个sleep()结束或通过interrupt()唤醒进入就绪状态。
2. 【CPU资源和锁资源释放不同】wait()方法释放CPU和锁资源,sleep()方法仅释放CPU资源但保存锁资源。
3. 【各类的工作机制不同】
一个运行态线程调用wait()方法进入等待阻塞状态被放入等待序列等待notify/notifyAll唤醒进入锁标志池中(用于锁机制)。
一个运行态线程调用sleep()方法进入其他阻塞状态一个sleep()结束或通过interrupt()唤醒进入就绪状态。
学而不思则罔,思而不学则殆!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具