wait和notify方法

目录

前言

一、wait()方法

wait()做的三件事

让wait()方法结束等待的条件

二、notify()方法

三、notifyAll()方法

总结

四、wait和sleep的对比【面试题】


前言

wait意思是等待,notify的意思是通知,它们的作用是协同多个线程的执行顺序

因为“抢占式执行”让两个线程的执行顺序充满了不确定性,所以我们希望通过wait和notify来控制线程的执行顺序,使线程之间可以更好的配合。

我们需要知道的是这两个方法都是Object(所以类的老祖宗)的方法

一、wait()方法

wait()做的三件事

1.让当前线程阻塞等待(把这个线程的PCB从就绪队列中放到阻塞队列中),准备接受通知

2.释放当前锁(要想使用wait()或者是notify(),就必须搭配synchronized,需要先获取到锁,然后才能谈wait())

3.需要满足一定的条件才能被唤醒,唤醒后重新尝试获取到这个锁

需要注意的是第一点和第二点需要以原子同时完成

让wait()方法结束等待的条件

1.其他线程调用该对象的notify()方法【最主要的用法】

我们已经知道了wait()和notify()都是Object的方法,就是说,如果线程1中的对象1调用了wait()方法,必须要有一个线程2,也调用对象1的notify()方法才能唤醒线程1,如果线程2调用对象2的notify()方法,是不能唤醒线程1的

public class ThreadDemo18 {
    public static void main(String[] args) throws InterruptedException {
        Object object=new Object();
        object.wait();
        object.notify();
    }
}

结果为

第一行的灰体带下滑线的意思是非法锁状态

如果没有把wait放到synchronized内部,就能看到这个异常

调用wait的对象和锁对象必须是同一个

public class ThreadDemo18 {
    public static void main(String[] args) throws InterruptedException {
        Object object=new Object();
        synchronized (object){
            System.out.println("wait之前");
            object.wait();
            System.out.println("wait之后");
        }

    }
}

结果为

 从结果我们可以看出现在这个线程已经进入了阻塞队列中,我们也可以从jconsole.exe看出这个线程正在进行等待

 如果我们不对这个程序做什么的话这个线程就会永远等待下去,此时我们需要做点什么来使得这个线程等待状态结束,这里我们引入了notify方法

二、notify()方法

关于notify方法的使用

1.也需要放到synchronized中使用

2.notify操作是一次唤醒一个线程,如果是有多个线程都在等待中,调用notify就相当于是随机唤醒了一个,其它线程保持原状

3.调用notify是通知对方被唤醒,但是调用notify方法的线程并不是立刻释放锁,而是要等待当前的synchronized代码块执行完才释放锁(notify本身不会释放锁)

代码实例

public class ThreadDemo19 {
    static class WaitTask implements Runnable{
        private Object locker=null;

        public WaitTask(Object locker) {
            this.locker = locker;
        }

        @Override
        public void run() {
            //进行wait的线程
            synchronized (locker){
                System.out.println("wait开始前");
                try {
                    //直接调用wait,相当于this.wait(),也就是针对WaitTask的对象进行等待
                    //但是我们需要在下面在NotifyTask类中针对同一个对象进行通知
                    //然而,在NotifyTask中拿到WaitTask的对象并不容易
                    locker.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("wait结束");
            }
        }
    }
    static class NotifyTask implements Runnable{
        private Object locker=null;

        public NotifyTask(Object locker) {
            this.locker = locker;
        }

        @Override
        public void run() {
            //进行notify的线程
            synchronized (locker){
                System.out.println("notify开始前");
                locker.notify();
                System.out.println("notify结束");
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        //所以为了解决上述问题,我们需要专门建一个对象,去负责加锁/通知操作
        Object locker=new Object();
        Thread t1=new Thread(new WaitTask(locker));
        Thread t3=new Thread(new WaitTask(locker));
        Thread t4=new Thread(new WaitTask(locker));
        Thread t2=new Thread(new NotifyTask(locker));
        t1.start();
        t3.start();
        t4.start();
        Thread.sleep(3000);
        t2.start();
    }
}

运行结果为

三、notifyAll()方法

notify方法一次只能唤醒一个线程,而notifyAll可以唤醒多个,虽然多个线程都被唤醒了,但这几个线程执行还是有先后顺序的原因是这几个线程还要竞争锁

public void run() {
            //进行notify的线程
            synchronized (locker){
                System.out.println("notify开始前");
                locker.notifyAll();
                System.out.println("notify结束");
            }
        }

运行结果为

2.wait()等待时间超时

3.其它线程调用该等待线程的interrupted()方法,导致wait抛出InterruptedExpectation异常

总结

notify是一次唤醒一个,而notifyAll是一次唤醒一堆,具体用哪个还要看具体场景,一般来说用的是notify

四、wait和sleep的对比【面试题】

1.sleep操作是指定一个固定时间来阻塞等待,而wait既可以指定时间,也可以无限等待

2.wait可以通过notify或interrupt或时间到来唤醒,sleep通过interrupt或时间到唤醒

3.wait的主要用途是为了协调线程之间的先后顺序,而sleep单纯是让线程休眠,并没涉及到多个线程的配合

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值