Java中的wait和notify

2023-12-15 15:32:18

前言

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知.
但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序

完成这个协调工作, 主要涉及到四个方法
wait() / wait(long timeout): 让当前线程进入等待状态.
notify() / notifyAll(): 唤醒在当前对象上等待的线程?

一.wait()方法

如果调用wait()方法,那么它会做以下三件事:

  1. 使当前执行代码的线程进行等待. (把线程放到等待队列中)
  2. 释放当前的锁
  3. 满足一定条件时被唤醒, 重新尝试获取这个锁

注意: wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.

也就是说,对象的引用调用wait, 首先这个对象一定是被加锁了

代码示例:

public class WaitANDNotify {
    public static void main(String[] args) throws InterruptedException {
        Object o1 = new Object();

        synchronized (o1) {
            System.out.println("wait 之前");
            //之所以吧wait放到synchronized里面,是要确保o1对象是拿到了锁的
            o1.wait();
            System.out.println("wait 之后");

        }
    }
}

此时如果没有别的线程去调用notify方法,那么代码会一直等待,执行不到“wait之后”

注意:wait方法调用后,该线程会主动放弃CPU和资源,进入等待状态;

????????线程调用wait方法后,会被加进等待池中,对应的状态是WAITING、TIMED_WAITING。

二.notify()方法

notify 方法是唤醒等待的线程.

  1. 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的。
  2. 其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
  3. 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到");
  4. 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁

代码示例:

class notify1 {
    public static void main(String[] args) {
        /**
         * wait操作了一下几步
         * 1.释放当前的锁
         * 2.让线程进入阻塞
         * 3.当线程被唤醒的时候,重新获取到锁   如果一次唤醒多个锁,那么就有可能是串行执行,按照一定的顺序进行重新获取到锁
         */
        Object object = new Object();   
        Thread t1= new Thread(() -> {
           synchronized (object) {
               System.out.println("wait 之前");
               try {
                   object.wait();  //此时已经释放了当前的锁了
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }

            System.out.println("wait之后");
        });

        Thread t2 = new Thread(() -> {
            try {
                System.out.println("等待了三秒,马上进行通知");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            synchronized (object) {   //此时object对象已经被wait解锁了,需要重新加锁
                System.out.println("进行通知");
                object.notify(); //唤醒锁
            }
        });

        t1.start();
        t2.start();
    }
}

运行结果:

?

代码解读:

  1. 此代码有一个对象object 和两个线程 t1 和 t2,t1 让object加锁并且进入了wait状态,t2负责唤醒object对象。
  2. 在唤醒 object对象时,由于它已经被wait操作释放锁了,此时需要重新加锁,然后调用 notify 方法,唤醒object对象

文章来源:https://blog.csdn.net/qq_65501447/article/details/134939956
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。