Java并发编程—线程间协作方式wait()/notify()/notifyAll()原理分析

本文深入分析了Java并发编程中的等待通知机制wait/notify,通过实例展示了线程间的交互过程,解释了wait、notify的工作原理,包括线程状态的变化以及同步队列与等待队列的概念。强调了wait、notify的使用顺序和加锁的重要性,并提供了相关注意事项。
摘要由CSDN通过智能技术生成

原文作者:tom有了cat

原文地址:java并发编程基础之等待通知机制wait/notify原理分析

一个线程修改了一个对象的值,而另一个线程感知了变化,然后进行了相应的操作,整个过程开始于一个线程,结束于另一个线程。前者是生产者,后者是消费者,这种模式在功能层面上实现了解耦。有下面一段代码,大家可以根据执行的结果和注释很清晰的明确这个wait和notify的工作机制,wait等待释放锁。代码如下,不再做具体描述:

package juc.waitsleep;
 
/**
 * @Description   测试notify和wait机制
 * @Author DJZ-WWS
 * @Date 2019/5/15 11:44
 */
public class WaitNotify {
    static  Object lock=new Object();
    static boolean flag=true;
 
    /**
     * 整个的一个执行流程wait线程先执行,执行到wait方法进行等待,进入等待队列,这时候释放锁,主线程休眠,
     * notify线程还没有开始进行工作,主线程休眠以后notify开始工作,由于wait已经将锁释放,所以notify会握住锁,
     * 执行了notify的业务以后将wait线程唤醒,这时候notify的业务还没有执行完,wait已经被唤醒,将进入阻塞队列,状态变为阻塞状态,
     * 后面notify进入二次加锁,等到这个里面的业务执行完以后,wait线程才能继续走后面的逻辑,从而将状态从阻塞变为运行
     *
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Thread waitThread = new Thread(new Wait(), "waitThread");
        waitThread.start();
        Thread.sleep(3000);
        Thread notifyThread = new Thread(new Notify(), "notifyThread");
 
        notifyThread.start();
    }
 
    static   class Wait implements   Runnable{
        @Override
        public void run() {
            //当条件不满足时继续wait,同时释放了lock锁
            synchronized (lock){
                while (flag){
                    try {
                        System.out.println(Thread.currentThread().getName()+" falg is true"+" wait 线程进入等待状态");
                        lock.wait();//执行以后线程变为阻塞状态
                        System.out.println("wait 被唤醒"+"线程的状态为"+Thread.currentThread().getState());
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
                //条件满足时完成工作
                System.out.println(Thread.currentThread().getName()+" flag is false ");
            }
        }
    }
 
    static class Notify implements Runnable{
        @Override
        public void run() {
            synchronized (lock){
                //获取lock的锁,然后进行通知,通知不会释放lock的锁
                //直到当前线程释放了lock后,WaitThread才能从wait方法中返回
                System.out.println("notify 握住了锁");
                lock.notifyAll();;
                flag=false;
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //再次加锁
            synchronized (lock){
                //这个地方等待线程不会立马从wait返回,而是需要等待notify或者notifyall的线程释放锁之后,等待线程才有机会从wait返回
                System.out.println(Thread.currentThread().getName()+" 再次得到一个锁");
                try {
                    System.out.println(Thread.currentThread().getName()+"我将要睡3秒");
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()+"睡醒了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
}

输出的内容如下:

一些细节的总结

  1. wait()、notifyAll()时需要先对调用对象加锁:因为需要先把线程加入到等待队列然后再释放锁。那么可以说一个线程只有获取到锁以后才能加入等待队列,所以wait执行的时候要先获取到锁
  2. wait、notify/notifyAll和sleep的区别与联系:前三个方法是Object的本地final方法,sleep方法是Thead类的静态方法。wait使当前线程阻塞,前提是必须先获得锁,所以只能在synchronized锁范围内里使用wait、notify/notifyAll方法,而sleep可以在任何地方使用
  3. notify和wait的顺序不能错,如果A线程先执行notify方法,B线程在执行wait方法,那么B线程是无法被唤醒的。
  4. 调用wait方法之后线程状态由Running变为waiting,将当前线程放置到对象的等待队列。
  5. notify或者notifyall方法调用后,等待线程不会从wait()方法返回,而是需要等到notify或者notifyall()的线程释放锁之后,等待线程才有机会从wait返回
  6. notify()方法将等待队列中的一个线程从等待队列移到同步队列,notifyall()方法将等待队列中的所有线程全部移到同步队列,被移动的线程状态由waiting变为blocking
  7. 从wait()返回的前提是获得了调用对象的锁。

工作原理如下图

wait线程首先获得了对象的锁,然后调用对象的wait方法,从而放弃了锁并进入了对象的等待队列WaitQueue,进入等待状态。由于wait线程释放了对象的锁,notify随后获取了对象的锁,并调用对象的notify方法,将等待线程移到SynchronizedQueue队列中,此时wait线程变为组神色状态。Notify释放了锁之后,wait线程再次获取到做并从wait()返回继续执行。

关于等待队列WaitQueu及SynchronizedQueue队列可以参考:Java并发编程—AQS原理分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值