Java Wait底层原理

在Java多线程编程中,线程同步是一个重要的概念。在多线程环境中,不同的线程并发执行时,可能会存在资源竞争的问题,为了避免多个线程同时修改某个共享资源而导致数据不一致或出现安全问题,我们需要使用同步机制来保证线程的安全性。

Java提供了waitnotify方法来实现线程的等待和唤醒操作,这是基于对象监视器(Object Monitor)的概念实现的。本文将介绍Java中wait方法的底层原理,并通过代码示例来说明其使用方法。

1. Java对象监视器

在Java中,每个对象都有一个与之关联的对象监视器,它是用来控制对该对象的访问的。每个对象只有一个对象监视器,它由Java虚拟机(JVM)内部实现。

对象监视器实际上是与对象关联的一种锁,它有两种状态:锁定非锁定。当一个线程访问一个对象的同步代码块时,它会尝试获取该对象的对象监视器,如果对象的对象监视器处于非锁定状态,那么线程就可以获取该锁,并将其置为锁定状态;否则,线程将进入阻塞状态,等待其他线程释放该对象的锁。

2. wait方法的使用

waitObject类中的一个方法,它用于使当前线程等待,直到另一个线程调用该对象的notifynotifyAll方法来唤醒它。

wait方法有以下几种重载形式:

public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException
  • 第一种形式的wait方法使当前线程一直等待,直到其他线程调用该对象的notifynotifyAll方法。

  • 第二种和第三种形式的wait方法使当前线程等待一段时间,在等待的过程中,如果超过指定的时间没有被其他线程唤醒,那么当前线程将自动唤醒。

在调用wait方法之前,线程必须先获得该对象的锁,否则会抛出IllegalMonitorStateException异常。

3. wait方法的底层原理

在Java的对象头中,有一个字段用于存储对象的监视器状态,它可以是无锁状态、锁定状态或者是等待状态。

当一个线程调用某个对象的wait方法时,它将会释放该对象的锁,并进入对象的等待集(Wait Set)。等待集是一个由该对象的对象监视器维护的线程集合,它用于存放那些调用了该对象的wait方法而进入等待状态的线程。

当另一个线程调用了该对象的notifynotifyAll方法时,JVM会从等待集中选择一个线程唤醒,然后将其从等待集中移除,并使之进入就绪状态。被唤醒的线程将重新尝试获取该对象的锁,一旦获取成功,它将继续执行。

4. 示例代码

下面是一个使用waitnotify方法的示例代码:

class SharedObject {
    private boolean ready = false;

    public synchronized void waitForReady() throws InterruptedException {
        while (!ready) {
            wait();
        }
    }

    public synchronized void setReady() {
        ready = true;
        notifyAll();
    }
}

class WaitThread extends Thread {
    private SharedObject sharedObject;

    public WaitThread(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }

    public void run() {
        try {
            sharedObject.waitForReady();
            System.out.println("Thread " + Thread.currentThread().getId() + " is woken up.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class NotifyThread extends Thread {
    private SharedObject sharedObject;

    public NotifyThread(SharedObject sharedObject) {