文章目录
- wait and notify(等待通知机制
- notify
- 补充
wait and notify(等待通知机制
引入wait notify就是为了能够从应用层面上,干预到多个不同线程代码的执行顺序,这里说的干预,不是影响系统的线程调度策略(内核里调度线程,仍然是无序调度)
相当于是在应用程序代码中,让后执行的线程,主动放弃被调度的机会,就可以让先执行的线程,先把对应代码执行完了
举例:
在ATM机上取钱
ATM通过锁来互斥
第一个人,先进去,发现ATM没钱,然后出来了,但是和其他人来竞争这个ATM,参与到了锁竞争中,此时完全有可能第一个人再次拿到这个锁,如果反复如此,就会导致第一个人反复获取到锁,但又无法完成实质性的逻辑,导致“线程饿死”。
这种情况就是严重的bug,当第一个人发现自己要执行的逻辑,前提条件不具备,在这种情况下,应该主动放弃对锁的竞争,一直到条件具备,此时再解除阻塞,参与锁竞争,这个时候就要用到wait和notify
join是等待另一个线程执行完,才继续执行
wait则是等待另一个线程通过notify进行通知(不要求另一个线程必须执行完)
wait进入阻塞,只能说明自己释放锁了
其他线程是否拿到了锁,另当别论
阻塞产生的原因有好几种:
1.sleep TIMED_WAITING
2.join/wait WAITING
3.synchronized BLOCKED
Object object = new Object();
object.wait();
随便拿一个对象都能调用wait但是运行起来会报异常
不合法监视状态异常
原因:wait一旦调用就会释放锁,释放锁的前提是拿到锁,所以,wait必须放到synchronized里面使用。
wait锁对象必须和synchronized锁对象一致
public class Test4 {
public static void main(String[] args) {
Object object = new Object();
Thread t1 = new Thread(()->{
synchronized (object){
System.out.println("wait前");
try {
object.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("wait后");
}
});
t1.start();
}
}
输出结果:
wait前
代码一直没有结束
在Java监视和管理控制台上:
notify
锁被wait就需要来唤醒锁,notify就是来唤醒锁的
notify可以不放在synchronized里面,但是Java规定notify必须放在synchronized里面
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
Thread t1 = new Thread(()->{
synchronized (object){
System.out.println("wait前");
try {
object.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("wait后");
}
});
Thread t2 = new Thread(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized(object){
System.out.println("notify前");
object.notify();
System.out.println("notify后");
}
});
t1.start();
t2.start();
}
}
运行结果:
wait前
notify前
notify后
wait后
线程2使用sleep的原因:
因为线程调度是随机的,不确定线程1还是线程2先运行,如果线程2先运行就达不到我们预期的结果,所以sleep线程2,让线程1先运行,先执行wait,再执行notify。
上述代码运行执行过程:
1.t1先执行起来后,就会立即拿到锁,并打印wait前,然后进入wait方法(释放锁+阻塞等待)
2.t2执行起来,先进行sleep五秒(为了让t1先拿到锁)
3.t2sleep结束后,由于t1是wait状态,锁是释放的,t2就能拿到锁,接下来打印notify前,执行notify操作,唤醒t1
4.由于t2还没有释放锁,t1想要获取锁,可能会出现阻塞,和t2锁竞争导致
5.t2打印notify后,释放锁,t2执行完毕,t1获取到锁,打印wait后
补充