更多内容请点击了解
本篇文章将详细讲述wait和notify的区别,请往下看
目录
更多内容请点击了解
文章目录
一、wait和notify概念
二、wait()方法详解
三、notify()方法详解
代码如下:
3.1notifyAll()详解
四、wait和sleep的对比
一、wait和notify概念
由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知,但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序
wait:让当前线程进入等待状态
notify:唤醒在当前对象上等待的线程
注意: wait, notify, notifyAll 都是 Object 类的方法.
wait和notify一定要搭配synchronized来使用,没有synchronized会抛出异常!!!
举个例子:
一群滑稽老铁准备去ATM取钱,一号老铁要取钱,进去之后,发现ATM没钱了,那么他出来了,一直等到ATM里面有钱再进去,那么接下来几号老铁进去拿钱就是随机的,不确定的,为了解决这个情况,可以使用wait和notify来解决。
二、wait()方法详解
wait做的事情:
- 使当前执行代码的线程进行等待. (把线程放到等待队列中)
- 释放当前的锁
- 满足一定条件时被唤醒, 重新尝试获取这个锁.
wait 结束等待的条件:
- 其他线程调用该对象的 notify 方法
- wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间)
- 其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常
代码如下:
public class waitDemo {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
synchronized (object) {
System.out.println("等待中");
object.wait();
System.out.println("等待结束");
}
}
}
可以发现程序一直在运行,没有停止,就说明一直在wait,这样在执行到object.wait()之后就一直等待下去,那么程序肯定不能一直这么等待下去了。这个时候就需要使用到了另外一个方法唤醒的方法notify()
wait还提供了一个带有参数的方法,参数指定的是最大等待时间,不带参数的wait就是死等,带参数的wait就会等最大时间之后,还没人通知,就自己唤醒自己。
使用wait,阻塞等待会让线程进入WAITING状态
三、notify()方法详解
notify 方法是唤醒等待的线程
- 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
- 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到")
- 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
代码如下:
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
Thread t1 = new Thread(() -> {
try {
System.out.println("wait 开始");
synchronized (locker) {
locker.wait();
}
System.out.println("wait 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
Thread.sleep(1000);
Thread t2 = new Thread(() -> {
synchronized (locker) {
System.out.println("notify 开始");
locker.notify();
System.out.println("notify 结束");
}
});
t2.start();
}
}
t1先执行,执行到wait,就阻塞了,1s后t2开始执行,执行到notify就会通知t1线程唤醒,(注意,notify是在synchronized内部,就需要t2释放了锁,t1才能继续往下走),加锁的是同一个locker
3.1notifyAll()详解
notify方法只是唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程,
可以有多个线程,等待同一个对象,唤醒之后,这三个线程就会重新竞争锁,然后依次执行
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
Thread t1 = new Thread(() -> {
try {
System.out.println("wait 开始");
synchronized (locker) {
locker.wait();
}
System.out.println("wait 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
Thread t3 = new Thread(() -> {
try {
System.out.println("wait3 开始");
synchronized (locker) {
locker.wait();
}
System.out.println("wait3 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t3.start();
Thread.sleep(1000);
Thread t2 = new Thread(() -> {
synchronized (locker) {
System.out.println("notify 开始");
locker.notifyAll();
System.out.println("notify 结束");
}
});
t2.start();
}
}
可见唤醒全部线程,全部执行完毕
四、wait和sleep的对比
wait有一个带参数的版本,用来体现超时时间,就感觉和sleep差不多。
- 他俩最大的区别就是在于初心不同,wait解决的是线程之间的顺序控制,sleep单纯是让线程休眠一会
- 另外,wait需要搭配锁使用,sleep不用