1、wait/notify 原理
- owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WATING状态。
- BLOCKED和WATING状态的线程都处于阻塞状态,不占用CPU时间片。
- BLOCKED状态线程,会在Owner线程释放锁时唤醒。
- WATING状态的线程会在Owner线程调用notify或者notifyAll时唤醒,但唤醒后并不会立即获取锁,会进入EntryList竞争锁资源。
2、API
- obj.wati():让进入object监视器的线程到WaitSet等待
- obj.wait(long timeout):让进入object监视器的线程到WaitSet等待,最多等待timeout 毫秒
- obj.notify():随机唤醒一个在object 上WaitSet中的等待的线程
- obj.notifyAll():唤醒全部在object 上WaitSet中的等待的线程
@Slf4j(topic = "w.WaitNotifyTest01")
public class WaitNotifyTest01 {
final static Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (obj) {
log.debug("执行代码...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("{} 线程其他代码...", Thread.currentThread().getName());
}
}, "t1").start();
new Thread(() -> {
synchronized (obj) {
log.debug("执行代码...");
try {
// 等待条件
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("{} 线程其他代码...", Thread.currentThread().getName());
}
}, "t2").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
synchronized (obj) {
// log.debug("条件满足,通知可以继续执行...");
// obj.notify();
log.debug("条件都满足,通知全部继续执行...");
obj.notifyAll();
}
}, "t3").start();
}
}
带参wait示例代码在后面。
3、wait(long n) 和 sleep(long n)区别
- wait是Object对象的方法,sleep是Thread类的静态方法
- wait需要和synchronized一起使用,sleep不需要。
- 对象调用wait,当前线程会释放锁对象;而sleep在睡眠的时候,不会释放锁对象。
4、唤醒不同条件下等待的多线程
简单场景描述:博主租住的小区现在正在改造,卡车司机王师傅在运送建筑垃圾,此时卡车没油了,需要等待其他人吧柴油送来继续干活;负责线路改造的李师傅,需要操作电转在墙壁上钻孔,但是电还没有接通,需要等待其他人把电接通。如果送油的先来了就通知王师傅,可以继续运行建筑垃圾了,如果电先接通了就通知李师傅继续钻孔。
代码如下:
@Slf4j(topic = "w.PostureStep01")
public class PostureStep03 {
static final Object room = new Object();
// 是否又电
static boolean hasElectric = false;
// 是否有柴油
static boolean hasDiesel = false;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (room) {
log.debug("电有了没?[{}]", hasElectric);
while (!hasElectric) {
log.debug("没电,先歇会!");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("电接通了?[{}]", hasElectric);
if (hasElectric) {
log.debug("开始干活!");
}
}
},"李师傅").start();
new Thread(() -> {
synchronized (room) {
log.debug("柴油送到没?[{}]", hasElectric);
while (!hasDiesel) {
log.debug("柴油没送到,先歇会!");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("柴油送到没?[{}]", hasElectric);
if (hasDiesel) {
log.debug("开始干活!");
}
}
},"王师傅").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
synchronized (room) {
hasElectric = true;
log.debug("电接通了!");
room.notifyAll();
}
}, "工人").start();
}
}