Java多线程基础-第一节5:wait和notify

Posted 我擦我擦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程基础-第一节5:wait和notify相关的知识,希望对你有一定的参考价值。

文章目录

由于线程之间的执行是抢占式的,所以线程之间的执行的先后顺序难以预知。但在实际开发中有时我们需要各个线程以特定的顺序执行,例如生产者与消费者模型中

  • 只有生产者线程生产出了产品消费者线程才能去取
  • 只有消费者线程消费了产品(有冗余空间后)生产者线程才能生产

在Java多线程中,要完成这个协调工作会涉及如下方法

  • wait()/wait(long timeout):让当前线程进入等待状态
  • notify():唤醒在当前对象上等待的线程
  • notifyAll():同上

注意:waitnotifynotifyAll都是Object类的方法,这意味着可以使用任意类的实例能都调用这些方法

一:wait()方法

wait()方法:线程执行到wait就会发生阻塞,直到另一个线程调用notify将此wait唤醒。wait要搭配synchronized使用,脱离synchronized使用wait会直接抛出异常。执行到wait会做以下三件事情

  • 释放当前的锁
  • 使线程进入等待
  • 满足一定条件,结束等待,尝试获取锁

wait结束等待的条件有

  • 其他线程调用该对象的notify方法
  • wait等待时间超时(wait(long timeout)
  • 其他线程调用该等待线程的interrupted方法,导致wait抛出InterruptedException

如下

public class TestDemo 
    public static void main(String[] args) 
        Object object = new Object();
        System.out.println("wait之前");
        synchronized (object)
            try 
                object.wait();
             catch (InterruptedException e) 
                throw new RuntimeException(e);
            
        
        System.out.println("wait之后");

    

二:notify()方法

notify()方法:用于唤醒等待的线程,需要在同步方法或同步块中调用。注意

  • 如果有多个线程等待,则由线程调度器随机挑选出一个处于wait状态的线程
  • notify方法之后,当前线程不会马上释放该对象锁,在退出同步代码块之后才会释放对象锁

如下是一个典型的例子

public class TestDemo 
    public static void main(String[] args) 
        //准备一个对象,需要保证wait和notify是同一个对象
        Object object = new Object();

        //第一个线程,进行wait操作
        Thread t1 = new Thread("t1")
            @Override
            public void run()
                while(true)
                    synchronized (object)
                        System.out.println(Thread.currentThread().getName() + "进入并占用锁,持续3s");
                        try 
                            Thread.sleep(3000);
                         catch (InterruptedException e) 
                            throw new RuntimeException(e);
                        
                        try 
                            System.out.println(Thread.currentThread().getName() + "等待并释放锁");
                            object.wait();
                         catch (InterruptedException e) 
                            throw new RuntimeException(e);
                        
                        System.out.println("等待结束," + Thread.currentThread().getName() + "重新获取到锁");
                    
                
            
        ;
        t1.start();

        //第二个线程,进行notify
        Thread t2 = new Thread("t2")
            @Override
            public void run()
                while(true)
                    synchronized (object)
                        System.out.println(Thread.currentThread().getName() + "进入并占用锁,持续3s");
                        try 
                            Thread.sleep(3000);
                         catch (InterruptedException e) 
                            throw new RuntimeException(e);
                        
                        System.out.println(Thread.currentThread().getName() + "进行notify");
                        object.notify();

                        System.out.println("notify完成,让" + Thread.currentThread().getName() + "歇3s");
                        try 
                            Thread.sleep(3000);
                         catch (InterruptedException e) 
                            throw new RuntimeException(e);
                        

                    
                    System.out.println(Thread.currentThread().getName() + "已处在synchronized外,再歇10s");
                    try 
                        Thread.sleep(12000);
                     catch (InterruptedException e) 
                        throw new RuntimeException(e);
                    

                
            
        ;

        t2.start();
    


下面是一个动图,展示了程序的运行过程

以上是关于Java多线程基础-第一节5:wait和notify的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程基础-第一节1:多线程概念和Java中创建线程的方式

Java多线程基础-第一节2:Thread类

Java多线程基础-第一节6:多线程案例

Java多线程基础-第一节4:synchronized关键字(监视器锁monitor lock)和volatile关键字

Java多线程常见面试题-第一节:锁策略CAS和Synchronized原理

Java多线程基础之wait,notify