多线程|wait、notify的使用

发布时间 2023-09-01 01:01:52作者: 司丝思

线程执行顺序的随机性的根本原因是随机调度和抢占式执行,但在开发的过程中,我们往往希望代码按照一定的顺序执行,因此Java中提供了一些可以控制线程执行顺序的方法,通过这些方法让线程主动阻塞,让出CPU资源。wait搭配notify使用就可以控制线程的执行顺序。

wait和notify如何使用呢?我们借助代码来说明。

 public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        Thread t1 = new Thread(() -> {
            System.out.println("t1 : wait之前");
            try{
                object.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("t1 :wait之后");

        });
        Thread t2 = new Thread(() -> {
            System.out.println("t2 : notify之前");
            try{
                Thread.sleep(3000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            object.notify();
            System.out.println("t2 :notify之后");

        });
        t1.start();
        t2.start();
    }

梳理上述代码的思路:首先明确wait、notify都是Object类的方法,因此在使用wait和notify的时候,要先创建Object对象再去调用。创建线程t1,调用wait方法,让线程t1进入阻塞,创建线程t2,调用notify方法唤醒线程t1,来看看执行结果:

 执行结果出现了非法的锁状态异常,为什么有这个异常?来看看wait的工作原理:

1、释放锁;

2、进行阻塞;

3、收到notify通知后,重新尝试锁,获取锁后,继续往下执行。

wait和notify的使用必须搭配锁来使用,我们在相应位置加上锁:

 public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        Thread t1 = new Thread(() -> {
            System.out.println("t1 : wait之前");
            synchronized (object){
                try{
                    object.wait();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("t1 :wait之后");
            }
        });
        Thread t2 = new Thread(() -> {
            System.out.println("t2 : notify之前");
            synchronized (object){
                try{
                    Thread.sleep(3000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                object.notify();
            }
            System.out.println("t2 :notify之后");

        });
        t1.start();
        t2.start();
    }

我们再次梳理代码的逻辑,创建线程t1,在t1线程中调用wait,创建线程t2,在t2线程中先让线程休眠3000ms,再调用notify唤醒线程t1,t1线程被唤醒之后,继续往下执行,也就是打印输出“t1:wait”之后,而上述的执行效果都是基于t1线程先执行的前提下才能实现的,由于线程的随机调度,线程t2有可能先于t1线程执行,执行到notify,若现在线程1还没执行到wait,那么此时notify是没有任何作用的,因此必须得让t1线程先执行到wait,解决方法是在t2线程前调用sleep。