目录
了解wait
通过字面意思 , wait 就是等待 , 在多线程中 wait 可用于多个线程之间,来控制多个线程之间的执行顺序.
wait : 主要做三件事
1 . 解锁 (意味着wait必须在加锁的情况下使用)
2 . 阻塞等待
3 . 等待唤醒, 重新获取锁
举个栗子 :
public class Demo1 {
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (object) {
System.out.println("t1 wait 前");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 wait 后");
}
});
t1.start();
}
}
唤醒关键字 notify
一 . wait 与 notify
notify 与 wait 进行配合 , notify 就是唤醒正在阻塞的线程.
注意 : notify 也是要在加锁的情况下使用
将上述代码进行改变 :
public class Demo1 {
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (object) {
System.out.println("t1 wait 前");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 wait 后");
}
});
t1.start();
Thread.sleep(1000);
synchronized (object) {
object.notify();
}
}
}
注意 : 上述代码中有一个非常重要的点 . Thread.sleep(1000)
试想一下如果没有这句sleep 代码又是怎样的效果
去掉sleep 执行效果 :
由于多线程的抢占式执行,我们不能确定到底那个线程先执行
如果main线程(主线程) 线程执行了object.notify() 那么效果就是上面的执行效果
这是因为由于程序先执行了notify操作, 再等t1线程去执行wait操作时, notify操作早已经执行结束了.
因此在编写多线程的代码时 一定要注意wait 和 notify 之间的配合
不能出现上述这样"空打一炮"的情况
附加 : 等线程处于wait 阻塞状态时 , 如果尝试调用interrupt修改线程的标志位, 这时因为线程处于阻塞状态 强行唤醒就会导致正在处于阻塞状态的线程报错,并解除阻塞状态
public class Demo1 {
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (object) {
System.out.println("t1 wait 前");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().isInterrupted());
System.out.println("t1 wait 后");
}
});
t1.start();
Thread.sleep(1000);
t1.interrupt();
}
}
注意 : 如果线程正在处于阻塞的状态下, 调用interrupt 方法时, 会产生报错, 并且修改标志位失败 , 原本处于阻塞的线程会尝试解除阻塞.
附加 : 除了notify 还有 notifyAll() : 唤醒所有处于wait阻塞等待的线程.
不建议使用这个方法, 因为唤醒的线程执行顺序不可控,.
二. wait 与 join
wait : 在锁的状态下, 常配合notify来调度线程之间的顺序.
join : 更偏向于让执行join方法的线程等待直到另一个线程执行完毕.
例如 : 在main线程中执行 t.join() 意思就是让main线程等待 t 线程执行完之后再去执行剩余部分的代码.
三. wait 与 sleep
wait 与 sleep
共同点 :
1 . 都有一个带参数的版本, 用来设置超时时间 .
2 . 都可以提前唤醒.
不同点 : 从设计的初心来讲 : wait 解决的是线程之间的顺序控制
sleep 单纯是让当前的线程休眠一会
wait 要搭配锁使用, sleep 不需要
wait 是Object 类中的一个方法, sleep 是Thread 类中的一个方法.
wait 被调用后当前线程进入BLOCK状态并释放锁, 并可以通过notify和notifyAll方法进行唤醒.
sleep 被调用后当前线程进入TIMED_WAIT状态, 不涉及锁相关的操作.