1. 关于wait notify
- 持有锁的线程发现条件不满足,调用 wait,即可进入 WaitSet 变为 WAITING 状态;
- BLOCKED 和 WAITING 的线程都处于阻塞状态,不占用 CPU 时间片;
- BLOCKED 线程会在 持有锁的线程释放锁时唤醒;
- WAITING 线程会在 持有锁的线程调用 notify 或 notifyAll 时唤醒,但唤醒后并不意味者立刻获得锁仍需进入EntryList 重新竞争。
2. wait和sleep的区别
相同:
- 线程的状态相同;都是阻塞状态
区别:
- wait是Object的方法;任何对象都可以直接调用;sleep是Thread的静态方法;
- wait必须配合synchronized关键字一起使用;如果一个对象没有获取到锁直接调用wait会异常;sleep则不需要;
- wait可以通过notify主动唤醒;sleep只能通过打断主动叫醒;
- wait会释放锁、sleep在阻塞的阶段是不会释放锁的。
3. 代码示例
package org.example;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TestWait {
static Object o = new Object();
static boolean aFlag = false;
static boolean bFlag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (o) {
log.debug("t1");
//一定要用while,如果用if,调用notifyAll后,此线程不管aFlag是不是true,都会继续执行代码
//即条件不满足,仍然继续执行代码
while (!aFlag) {
log.debug("t1:wait");
try {
//使用wait可以释放锁,不影响其他线程工作,如果用sleep,不释放锁,其他线程无法工作
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("aFlag={}",aFlag);
}
}, "t1").start();
new Thread(() -> {
synchronized (o) {
log.debug("t2");
while (!bFlag) {
log.debug("t2:wait");
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("bFlag={}",bFlag);
}
}, "t2").start();
for (int i = 0; i < 3; i++) {
new Thread(() -> {
synchronized (o) {
log.debug("new Thread");
}
}, "a" + i).start();
}
Thread.sleep(1000);
new Thread(() -> {
synchronized (o) {
bFlag = true;
log.debug("唤醒所有wait");
//notifyAll唤醒所有wait的线程,notify只能随机唤醒某一个
o.notifyAll();
}
}, "t3").start();
}
}
- 查看打印