前言
我们都知道在多线程中有这么一个概念:就是每个对象都有一个wait()方法,这个方法会使得对应的线程进入block状态。那么线程调用wait()方法后为什么会进入block状态呢?以及进入block状态后被唤醒会怎么样呢?接下来将我们一起探讨一下这个问题
一、waitset的概念
线程的synchronized同步代码块里,monitor调用wait()方法后,该线程就会被存入monitor对象的waitset里,让线程进入block状态。
二、例子
1.代码例子
代码如下(示例):
public static void main(String[] args) throws InterruptedException {
// new Thread() {
// @Override
// public void run() {
// work();
// }
// }.start();
//
// Thread.sleep(1000);
// synchronized (LOCK) {
// LOCK.notify();
// }
IntStream.rangeClosed(1, 10).forEach(i ->
new Thread(String.valueOf(i)) {
@Override
public void run() {
synchronized (LOCK) {
try {
Optional.of(Thread.currentThread().getName() + " will come to wait set.").ifPresent(System.out::println);
LOCK.wait();
Optional.of(Thread.currentThread().getName() + " will leave to wait set.").ifPresent(System.out::println);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start()
);
Thread.sleep(3000);
IntStream.rangeClosed(1, 10).forEach(i ->
{
synchronized (LOCK) {
LOCK.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
);
}
}
2.waitset解读
1、所有对象都有一个waitset,用来存放调用了该对象的wait()方法之后进入block状态的线程
2、线程进入block状态后,需要其它线程调用notify()方法进行唤醒。被唤醒后需要重新排队获取锁,因此不会立马执行
3、线程从waitset中被唤醒的顺序不一定是FIFO
4、线程被唤醒后,不会立马被执行,需要排队抢锁。线程wait后会进行代码地址记录,当线程被唤醒抢到锁后会从记录的地址继续执行。