Java等待通知机制的工作原理

Java中Object类提供了wait/notify/notifyAll方法,配合synchronized方法,可以实现等待/通知机制。本文将介绍等待/通知机制的一般模板和工作原理。

Synchronized锁的工作机制

首先来看一下Synchronized锁的工作机制。
Synchronized锁的工作机制

如上图所示:

在Java中,任意一个对象都拥有自己的监视器。当这个对象被同步块或这个对象的同步方法调用时,执行方法的线程必须先获取到这个对象的监视器 才能进入同步块或同步方法。没有获得监视器的线程将会被阻塞在同步块和同步方法的入口处(即进入同步队列),并且变为Block状态

等待通知机制的一般模式

等待方

  1. 获取对象的锁
  2. 如果条件不满足,则调用该对象的wait方法,等待条件成熟
  3. 后续检查中发现条件满足,继续执行后面的逻辑

通知方

  1. 获取对象的锁
  2. 执行逻辑,改变条件
  3. 通知所有等待在该对象上的线程

等待方和通知方获取锁的对象应当是同一个对象,才能获取相应的通知信息。

示例代码如下:

public class Test {
    
    
    final static Object object = new Object();

    public static class WaitThread extends Thread {
    
    
        @Override
        public void run() {
    
    
            synchronized (object) {
    
    
                try {
    
    
                    System.out.println(System.currentTimeMillis() + ":waitThread wait for object!");
                    //  wait会释放锁
                    object.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis() + ":waitThread end!");
            }
        }
    }

    public static class NotifyThread extends Thread {
    
    
        @Override
        public void run() {
    
    
            synchronized (object) {
    
    
                System.out.println(System.currentTimeMillis() + ":notifyThread run!");
                object.notify();
                try {
    
    
                    // notify之后并不会释放锁,只是通知可以将线程从等待队列迁移至同步队列
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                // synchronized结束,object上的锁才释放
                System.out.println(System.currentTimeMillis() + ":notifyThread end!");
            }
        }
    }

    public static void main(String[] args) {
    
    
        Thread waitThread = new WaitThread();
        Thread notifyThread = new NotifyThread();
        waitThread.start();
        notifyThread.start();
    }
}

那么wait/notify和synchronized机制到底是如何协调工作的呢?

请看下图:

等待通知机制的工作原理

等待通知机制原理

在上图中,笔者根据代码逻辑,将线程waitThread和notifyThread的运行流程使用数字都标识了出来。大体流程如下:

根据synchronized锁定原理,只有通过Monitor.Enter成功的对象,才能执行后续的流程。在示例代码中,waitThread先获取到了object对象的监视器,但是随后调用了wait方法,导致waitThread让出了锁,并进入了等待队列。

与此同时知notifyThread正好可以拿到object对象的监视器,从而执行自己后续的逻辑。在最终条用notify方法,“唤醒”了waitThread,从而使得waitThread从等待队列中移到了同步队列。等到notifyThread中释放了锁(Synchronized代码块结束),waitThread才能从同步队列中出队,竞争到object对象的监视器,从而继续走后续的流程。

以上就是等待/通知机制的一般流程,总结原理如下:

  • 使用wait/notify/notifyAll方法时,需要先对调用对象加锁
  • 调用wait方法,当前线程状态由RUNNABLE变为WAITING,并将当前线程放到对象的等待队列中
  • notify/notifyAll方法会将等待队列中的一个/全部等待线程移动到同步队列中。但这些等待线程并不会立即从wait方法返回,而是需要notify/notifyAll的线程释放锁之后,才能从wait方法返回。

猜你喜欢

转载自blog.csdn.net/somehow1002/article/details/113141795