Java并发编程入门到精通--理解Java的wait和Notify机制
小职 2021-09-27 来源 :爱学习的宅男 阅读 441 评论 0

摘要:本篇主要介绍了Java并发编程入门到精通--理解Java的wait和Notify机制,通过具体的内容展现,希望对Java开发的学习有一定的帮助。

本篇主要介绍了Java并发编程入门到精通--理解Java的wait和Notify机制,通过具体的内容展现,希望对Java开发的学习有一定的帮助。

Java并发编程入门到精通--理解Java的wait和Notify机制

简单介绍

wait方法

wait方法的作用是使当前执行代码的线程进行等待,它是Object类的方法,该方法用来将当前线程置入等待队列中,并且在wait所在的代码行处停止执行,直到接到通知或被中断为止。

 

该方法只能在同步方法或同步块中调用(即需要先获得对象的监视器锁,一般来说在 synchronized 代码块或者synchronized修饰的方法中使用),否则抛出异常

 

IllegalMonitorStateException。

 

在A线程中调用Lock对象的wait方法以后,会释放Lock对象的监视器锁,同时将A线程放置于Lock对象的等待队列,A线程进入WAITING状态(Thread状态查看系列一)。

 

notify/notifyAll方法

notify/notifyAll方法的作用是唤醒执行对象的等待列表中的一个/所有线程,将其唤醒继续工作。

 

同样的,notify/notifyAll方法也只能在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的监视器锁。

 

在B线程中调用Lock对象的notify/notifyAll方法以后,Lock对象等待队列中的A线程从WAITING状态进入BLOCKED状态,而不是直接进入RUNNABLE状态。只有等B线程释放了Lock对象的监视器锁,并且A线程拿到以后,才进入到RUNNABLE状态。所以在编程中,尽量在使用了notify/notifyAll() 后立即释放对象的监视器锁,以便让其他线程获得锁进入RUNNABLE状态。

 

其他注意事项

wait、notify/notifyAll 方法是Object的本地final方法,无法被重写。

 

notify 和wait 的顺序不能错,如果A线程先执行notify方法,B线程再执行wait方法,那么B线程是无法被唤醒的。

 

实例详解

 

public class WaitThread extends Thread {

 

    private Object lock;

 

    public WaitThread(Object lock) {

        this.lock = lock;

    }

 

    @Override

    public void run() {

        synchronized (lock) {

            System.out.println("WaitThread开始执行run方法");

            try {

                System.out.println("WaitThread开始执行wait方法");

                lock.wait();

                System.out.println("WaitThread被唤醒");

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

}

public class NotifyThread extends Thread {

 

    private Object lock;

 

    public NotifyThread(Object lock) {

        this.lock = lock;

    }

 

    @Override

    public void run() {

        System.out.println("NotifyThread开始执行run方法");

        try {

            System.out.println("NotifyThread睡眠2秒");

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        synchronized (lock) {

            System.out.println("NotifyThread开始执行notify方法");

            lock.notify();

            try {

                System.out.println("NotifyThread执行notify方法后继续睡眠2秒");

                Thread.sleep(2000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println("NotifyThread睡眠2秒结束,并释放对象监视器锁");

        }

    }

}

public class Main {

    public static void main(String[] args) {

 

        Object lock = new Object();

 

        // 创建2个线程

        WaitThread waitThread = new WaitThread(lock);

        NotifyThread notifyThread = new NotifyThread(lock);

        // 启动他们

        waitThread.start();

        notifyThread.start();

    }

}

NotifyThread开始执行run方法

WaitThread开始执行run方法

WaitThread开始执行wait方法

NotifyThread睡眠2秒

NotifyThread开始执行notify方法

NotifyThread执行notify方法后继续睡眠2秒

NotifyThread睡眠2秒结束,并释放对象监视器锁

WaitThread被唤醒

WaitThread在拿到lock的监视器锁以后调用wait方法。

 

NotifyThread在启动以后先睡眠2秒,保证了notify方法在wait方法后面。

 

NotifyThread执行notify方法后继续睡眠2秒,这个时候NotifyThread并没有释放Lock的监视器锁,因此WaitThread处于BLOCKED状态并没有被真正被唤醒。

 

NotifyThread睡眠2秒结束,并释放对象监视器锁,这个时候NotifyThread取到Lock的监视器锁并进入到RUNNABLE状态。

 

进阶思考

如果A线程获得了多个对象的监视器锁,然后调用其中1个对象的wait方法,是释放所有对象的锁还是只释放调用的那个对象的锁呢?

 

我们一起通过一个示例来进行一下测试。

 

public class WaitThread extends Thread {

 

    private Object lock;

    private Object other;

 

    public WaitThread(Object lock, Object other) {

        this.lock = lock;

        this.other = other;

    }

 

    @Override

    public void run() {

        synchronized (lock) {

            synchronized (other) {

                System.out.println("WaitThread开始执行run方法");

                try {

                    System.out.println("WaitThread开始执行wait方法");

                    lock.wait();

                    System.out.println("WaitThread被唤醒");

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }

    }

}

public class NotifyThread extends Thread {

 

    private Object lock;

    private Object other;

 

    public NotifyThread(Object lock, Object other) {

        this.lock = lock;

        this.other = other;

    }

 

    @Override

    public void run() {

        System.out.println("NotifyThread开始执行run方法");

        try {

            System.out.println("NotifyThread睡眠2秒");

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        synchronized (lock) {

            System.out.println("NotifyThread获得lock锁");

 

            synchronized (other) {

                System.out.println("NotifyThread获得other锁");

                System.out.println("NotifyThread开始执行notify方法");

                lock.notify();

                try {

                    System.out.println("NotifyThread执行notify方法后继续睡眠2秒");

                    Thread.sleep(2000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                System.out.println("NotifyThread睡眠2秒结束,并释放对象监视器锁");

            }

        }

    }

}

public class Main {

    public static void main(String[] args) {

 

        Object lock = new Object();

        Object other = new Object();

 

        // 创建2个线程

        WaitThread waitThread = new WaitThread(lock, other);

        NotifyThread notifyThread = new NotifyThread(lock, other);

        // 启动他们

        waitThread.start();

        notifyThread.start();

    }

}

WaitThread开始执行run方法

WaitThread开始执行wait方法

NotifyThread开始执行run方法

NotifyThread睡眠2秒

NotifyThread获得lock锁

WaitThread线程拿到lock和other的对象锁以后,执行了lock的wait方法。NotifyThread线程在睡眠2秒后,仅拿到了lock锁,说明wait方法只释放了被执行对应的锁,这样就造成了死锁。

 

因此如果使用wait和notify机制时,一定要确认Wait线程和Notify线程获取对象锁的情况,尽量避免在获取多个对象锁的情况下使用,防止造成死锁问题。


我是小职,记得找我

✅ 解锁高薪工作

✅ 免费获取基础课程·答疑解惑·职业测评

Java并发编程入门到精通--理解Java的wait和Notify机制

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程