概述
当前线执行的执行的时候,遇到了wait方法,就会释放锁,进入阻塞状态,这个线程就会被放到waitset存起来,
其实这个waitset是不存在的一个数据结构,只是方便理解,有些人就提出了这么个概念
java 官方的一个描述(wait方法)
This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object.
wait set几点说明
- 所有对象都会由有个wait set,用来存放该对象wait方法之后的进入block状态的线程
- 线程被notify之后,不一定立即执行,需要抢锁
- 线程从wait set被唤醒的顺序不一定是FIFO
- 线程被唤醒后,必须重新获取锁,但是并不是从获取锁的地方执行,而是从wait的地方开始执行,也就说jvm会记录每个线程wait的位置
测试:线程从wait set被唤醒的顺序不一定是FIFO
package study.wyy.concurrency.thread.waitset;
import lombok.extern.slf4j.Slf4j;
import java.util.stream.IntStream;
/**
* @author :wyaoyao
* @date : 2020-04-11 10:10
*/
@Slf4j
public class Test1 {
// 定义一个锁
private static final Object LOCK = new Object();
public static void main(String[] args) throws InterruptedException {
// 模拟9个线程,进行wait
IntStream.rangeClosed(1, 9).forEach(i ->
new Thread(String.valueOf(i)) {
@Override
public void run() {
synchronized (LOCK){
try {
log.info("{} will place to wait set",Thread.currentThread().getName());
LOCK.wait();
log.info("{} will leave off wait set",Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start());
// 休眠一会,进行唤醒
Thread.sleep(3000);
IntStream.rangeClosed(1,10).forEach(i->{
synchronized (LOCK){
LOCK.notify();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
日志输出
[1] INFO study.wyy.concurrency.thread.waitset.Test1 - 1 will place to wait set
[7] INFO study.wyy.concurrency.thread.waitset.Test1 - 7 will place to wait set
[6] INFO study.wyy.concurrency.thread.waitset.Test1 - 6 will place to wait set
[5] INFO study.wyy.concurrency.thread.waitset.Test1 - 5 will place to wait set
[4] INFO study.wyy.concurrency.thread.waitset.Test1 - 4 will place to wait set
[3] INFO study.wyy.concurrency.thread.waitset.Test1 - 3 will place to wait set
[2] INFO study.wyy.concurrency.thread.waitset.Test1 - 2 will place to wait set
[9] INFO study.wyy.concurrency.thread.waitset.Test1 - 9 will place to wait set
[8] INFO study.wyy.concurrency.thread.waitset.Test1 - 8 will place to wait set
[1] INFO study.wyy.concurrency.thread.waitset.Test1 - 1 will leave off wait set
[6] INFO study.wyy.concurrency.thread.waitset.Test1 - 6 will leave off wait set
[7] INFO study.wyy.concurrency.thread.waitset.Test1 - 7 will leave off wait set
[8] INFO study.wyy.concurrency.thread.waitset.Test1 - 8 will leave off wait set
[9] INFO study.wyy.concurrency.thread.waitset.Test1 - 9 will leave off wait set
[2] INFO study.wyy.concurrency.thread.waitset.Test1 - 2 will leave off wait set
[3] INFO study.wyy.concurrency.thread.waitset.Test1 - 3 will leave off wait set
[4] INFO study.wyy.concurrency.thread.waitset.Test1 - 4 will leave off wait set
[5] INFO study.wyy.concurrency.thread.waitset.Test1 - 5 will leave off wait set
会发现不是先进先出的顺序
测试:
package study.wyy.concurrency.thread.waitset;
import lombok.extern.slf4j.Slf4j;
/**
* @author :wyaoyao
* @date : 2020-04-11 10:21
*/
@Slf4j
public class Test2 {
// 定义一个锁
private static final Object LOCK = new Object();
private static void work(){
synchronized (LOCK){
log.info("begining ......");
try {
log.info("Thread will coming");
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.info("Thread will out");
}
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
work();
}).start();
Thread.sleep(1000);
synchronized (LOCK){
LOCK.notify();
}
}
}
[Thread-0] INFO study.wyy.concurrency.thread.waitset.Test2 - begining ......
[Thread-0] INFO study.wyy.concurrency.thread.waitset.Test2 - Thread will coming
[Thread-0] INFO study.wyy.concurrency.thread.waitset.Test2 - Thread will out
可见线程wait唤醒之后,虽然会去抢锁执行,但是执行的时候,还是会从wait的地方开始执行,没有再次打印
begining …