等待唤醒机制
一、线程状态概述
public static enum **Thread.State**extends Enum<Thread.State>
线程状态。线程可以处于下列状态之一:
-
NEW
至今尚未启动的线程处于这种状态。 -
RUNNABLE
正在 Java 虚拟机中执行的线程处于这种状态。 -
BLOCKED
受阻塞并等待某个监视器锁的线程处于这种状态。 -
WAITING
无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。 -
TIMED_WAITING
等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。 -
TERMINATED
已退出的线程处于这种状态。在给定时间点上,一个线程只能处于一种状态。这些状态是虚拟机状态,它们并没有反映所有操作系统线程状态。
二、等待唤醒案例分析
线程质检之间的通信:
- 创建一个顾客线程:买包子,告知包子的种类和数量,调用wait方法。
- 创建一个老板线程:卖包子,花了5秒做包子,做好包子后调用notify方法,唤醒顾客拿走包子。
注意事项:
- 顾客和老板必须使用同步代码块包裹起来,保证等待和唤醒能有一个在执行。
- 同步使用的锁对象必须保证唯一
- 只用锁对象才能调用wait和notify方法
方法:
1.无参
public final void wait()
throws InterruptedException在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。
public final void notify()唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
package com.yuwendeng.ThreadTongbu;
public class DemoWaitAdnNotfiny {
public static void main(String[] args) {
Object obj = new Object();
new Thread(){
@Override
public void run() {
synchronized (obj){
System.out.println("告知包子种类和数量");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("包子开吃");
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj){
System.out.println("做好了包子,告知顾客可以拿走了");
obj.notify();//唤醒之后会继续执行wait之后的方法
}
}
};
}
}
2.带参
2.1 wait在毫秒值结束之后如果还没有被唤醒就会自动唤醒。sleep华星后进入到Runable/blocked状态
public final void wait(long timeout)
throws InterruptedException
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
obj.wait(5000);
2.2 notifyAll如果有多个等待线程,唤醒所有等待线程,notify 随机唤醒一个。
public final void notifyAll()唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
三、线程间通信
**概念:**多个线程在处理同一个资源,但是处理的动作却不同。
**为什么要处理线程通信:**多个线程并发执行时,是随机切换线程的,当我们需要多个线程共同完成一个任务时,是希望他们有规律的,需要多个线程之间互相通信。
**如何保证:**使用等待唤醒机制。
1.等待唤醒机制概述
2.用到的方法
- wait:线程不在活动,不再参与调度(ready queue),进入wait set,线程状态Waitting .等待别的线程执行 notify.
- notify:选取所统治对象的wait set中的一个线程释放;例如:有空位置之后,唤醒等待时间最久的线程。
- notifyAll:释放所统治对象的wait set上的全部线程。
**注意:**哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步快内的,而此刻它已经不再持有锁。
- 如果能获取锁,线程就从WAITING 状态变为RUNNABLE状态。
- 否则,从wait set 出来,又进入entry set,线程就从WAITING状态变为BLOCKED状态。