为什么要协调线程执行顺序
wait和notify是多线程编程中的重要工具,多线程调度是随机的,很多时候希望多个线程能够按照我们规定的顺序来执行,完成线程之间的配合工作
注意事项
1.要想让notify能够顺利唤醒wait,就需要确保wait和notify是同一个对象调用的,所以哪个对象调用wait和notify方法不重要,重要的是同一个对象调用
2.wait和notify都需要放到synchronized之内
wait在执行的时候,会做三件事,1.解锁,2.阻塞等待,3.等待其他的线程调用notify被唤醒,就会尝试重新加锁,加锁成功,wait执行完毕,继续执行后面的逻辑
因为wait在执行的时候要解锁,所以wait需要放到synchronized之内,虽然notify不涉及解锁,但也强制要求要放到synchronized中
3.如果进行notify的时候,没有线程处于wait状态,就相当于没用(也没有副作用)
wait与sleep之间的区别
sleep有一个明确的时间,到达时间,自然就会被唤醒,也能提前唤醒,使用interrupt提前唤醒
wait默认就是一直死等,一直等到有其他线程notify,wait也能被interrupt提前唤醒
不过wait也有带超时时间的版本,等待一定的时间就直接执行之后的代码
协调多个线程之间的执行顺序,当然还是优先考虑wait-notify而不是sleep
一些细节
如果此时有多个线程处于waiting的状态,而一个线程调用了notify方法,那么就会随机唤醒一个线程,而notifyall可以唤醒所有的线程,唤醒所有的线程后,线程们再争夺上锁的机会
如果我们想要唤醒一个指定的线程怎么办呢?
可以让不同线程使用不同的对象来进行wait,想唤醒哪个线程,就可以用对应的对象调用notify方法
通过wait和notify来协调线程执行顺序的代码案例
package 协调线程执行顺序;
import com.sun.source.tree.SynchronizedTree;
/**
* Created with IntelliJ IDEA.
* Description:
* User: wuyulin
* Date: 2023-07-26
* Time: 17:44
*/
public class Demo1 {
private static Object locker=new Object();
public static void main(String[] args) {
Thread A=new Thread(()->{
synchronized(locker){
System.out.println("A wait 开始执行");
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("A wait 执行结束");
}
});
Thread B=new Thread(()->{
synchronized(locker){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("B notify 开始");
locker.notify();
System.out.println("B notify 结束");
}
});
A.start();
B.start();
}
}