多线程wait

时间:2022-10-16 01:08:25

目录

了解wait

一 . wait 与 notify

二.  wait 与 join

三.  wait 与 sleep


了解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();
    }
}

多线程wait

多线程wait

 唤醒关键字 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();
        }
    }
}

多线程wait

多线程wait

注意 : 上述代码中有一个非常重要的点 . Thread.sleep(1000) 

试想一下如果没有这句sleep 代码又是怎样的效果

去掉sleep 执行效果 :

多线程wait

由于多线程的抢占式执行,我们不能确定到底那个线程先执行

如果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();
    }
}

多线程wait

注意 : 如果线程正在处于阻塞的状态下, 调用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状态, 不涉及锁相关的操作.