线程阻塞等待和唤醒(wait和notify)

15.wait和notify

线程的调度是无序的、随机的,抢占式执行的,但在实际的生活中,我们在某些情况下是需要有序执行的。那对于这种情况又该如何去解决呢?

wait方法:发现条件不满足或者说时机不成熟的时候就要阻塞等待。(让某个线程暂停下来等一等)

notify方法:其他线程构造了一个成熟的条件,可以唤醒等待。(把该线程唤醒,继续执行)

就比如说车辆行驶是无序的,随机的,有的车超速、抢占式的要往前跑,每个车都是一个独立的线程,但是当遇到红灯了,那么此时走在最前面的车辆就得停下等待,相应的后面的车也会跟着阻塞等待。只有当绿灯亮起,第一辆车被唤醒了,那么就可以通过了,紧接着就是后面的车辆陆陆续续的跟上过红绿灯。在这个过程中,第一辆车来讲也就是刚开始是wait()阻塞等待的,当绿灯亮起的时候,notify()让它唤醒,继续开始行驶。

注意:wait和notify都是Object对象的方法。只要是个类对象,都可以使用wait和notify。

wait方法的使用必须搭配synchronized使用,放在synchronized代码块里面,不然就会抛出以下异常
在这里插入图片描述
这个异常指的是非法锁状态异常,也就是说你还没获取到锁,就尝试去解锁,所以在这里可以清楚的知道在使用wait()方法的时候,必须要配合synchronized使用,因为wait()方法要做的事就包括解锁、阻塞等待、唤醒。
在这里插入图片描述
在添加了synchronized后,我们发现没有抛出异常了,但是这个线程确实一直在等待中,根据实际需要一直等待肯定是不行的,所以我们需要去唤醒这个线程,让他继续工作,在这里就使用的是notify()方法去唤醒。

package notebook;

public class ThreadTest15 {
    public static void main(String[] args) throws InterruptedException{
        Object object = new Object();
        Thread thread1 = new Thread(() -> {
            try {
                System.out.println("wait 开始");
                synchronized (object) {
                    System.out.println("等待中");
                    object.wait();
                }
                System.out.println("wait 结束");
            }catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        thread1.start();

        Thread.sleep(2000);
        Thread thread2 = new Thread(() -> {
           synchronized (object) {
               System.out.println("notify 开始");
               System.out.println("唤醒");
               object.notify();
               System.out.println("notify 结束");
           }
        });
        thread2.start();

    }
}

在这里插入图片描述
在这段代码中,主线程启动了thread1和thread2两个线程,在线程1中进行wait()阻塞,在释放锁后,thread2执行notify()方法去唤醒,将thread1从wait()方法中唤醒出来,继续往下执行。同时在这段代码中,因为线程之间的通信是通过共享object这个对象实现的,所以wait()方法会释放当前线程的锁,进入到等待状态,知道线程2调用了notify()方法唤醒,让其继续执行。

16.notifyAll()方法

notify()方法是唤醒某一个线程等待的,使用notifyAll()方法可以一次唤醒所有的等待线程。比如下面的例子,在上面代码中进行更改。

package notebook;

public class ThreadTest15 {
    public static void main(String[] args) throws InterruptedException{
        Object object = new Object();
        Thread thread1 = new Thread(() -> {
            try {
                System.out.println("wait 开始");
                synchronized (object) {
                    System.out.println("等待中");
                    object.wait();
                }
                System.out.println("wait 结束");
            }catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        thread1.start();

        Thread thread3 = new Thread(() -> {
            try {
                System.out.println("wait 开始2");
                synchronized (object) {
                    System.out.println("等待中2");
                    object.wait();
                }
                System.out.println("wait 结束2");
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread3.start();

        Thread thread4 = new Thread(() -> {
            try {
                System.out.println("wait 开始3");
                synchronized (object) {
                    System.out.println("等待中3");
                    object.wait();
                }
                System.out.println("wait 结束3");
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread4.start();

//        唤醒线程
        Thread.sleep(3000);
        Thread thread2 = new Thread(() -> {
            synchronized (object) {
                System.out.println("notifyAll 开始");
                System.out.println("唤醒所有等待线程");
                object.notifyAll();
                System.out.println("notifyAll 结束");
            }
        });
        thread2.start();



    }
}

在这里插入图片描述

17.wait()和sleep()的对比(重要)

wait()方法有一个带参数的版本是用来体现超时时间的,相对于sleep()来将sleep()它是体现的是当前线程休眠的时间,这两个一个是用于线程之间的通信的,一个是让线程阻塞等待一段时间。它们共同点也就是都让线程停止执行一段时间。但我们要清楚的知道这两个是要解决什么问题。wait()是要解决的是线程之间的顺序控制,sleep()只是单纯的让当前线程休眠一会。并且wait()需要搭配synchronized使用,sleep()不需要,wait()是Object的方法,sleep()是Thread的静态方法。
以上就是关于线程阻塞等待和唤醒的一些记录,可能存在很多不足,请见谅啦。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小哈不会玩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值