多线程的waitset介绍
waitset 在线程wait()方法执行后,会被放入被锁对象的一个waitset里面去,而当前wait()的位置也会被记录。
private final static Object object = new Object();
IntStream.rangeClosed(1, 10).forEach(s -> {
new Thread(() -> {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " --- > will wait ....");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " --- > will leave ....");
}
}).start();
});
try {
Thread.sleep(4_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
IntStream.rangeClosed(1, 10).forEach(s -> {
new Thread(() -> {
synchronized (object) {
object.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
});
}
验证线程从wait set中被唤醒的顺序不一定是FIFO
Thread-1 --- > will wait ....
Thread-0 --- > will wait ....
Thread-8 --- > will wait ....
Thread-5 --- > will wait ....
Thread-9 --- > will wait ....
Thread-4 --- > will wait ....
Thread-2 --- > will wait ....
Thread-3 --- > will wait ....
Thread-7 --- > will wait ....
Thread-6 --- > will wait ....
Thread-1 --- > will leave ....
Thread-6 --- > will leave ....
Thread-7 --- > will leave ....
Thread-3 --- > will leave ....
Thread-2 --- > will leave ....
Thread-4 --- > will leave ....
Thread-9 --- > will leave ....
Thread-5 --- > will leave ....
Thread-8 --- > will leave ....
Thread-0 --- > will leave ....
线程被唤醒后,必须重新去获取锁,会记录之前wait的位置,在wait的位置继续往下执行
private final static Object object = new Object();
void work() {
synchronized (object) {
System.out.println(" 开始执行 work ");
try {
object.wait(); //此处等待后,再次回唤醒后继续从当前位置执行。
System.out.println(" wait 。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 结束执行 work ");
}
}
结果
开始执行 wait
wait 。。。
结束执行 wait
结论
1、所有的对象都会有一个wait set,用来存放调用了该对象的wait方法之后进入block状态的线程
2、wait() 调用者是Lock对象,是释放锁的;sleep() 调用者是线程自己,但不释放锁。
3、线程被notify唤醒后,不一定立即执行。
唤醒顺序不是FIFO。
当线程重新获得锁后,也不会从头开始执行,而是从wait处之后的代码开始继续执行(执行地址恢复)。