📜  已将握手入队后无法将握手入队 (1)

📅  最后修改于: 2023-12-03 15:09:41.678000             🧑  作者: Mango

已将握手入队后无法将握手入队

在多线程编程中,握手(handshake)是一种常用的同步机制。它在两个线程之间传递信号,确保它们达成共识后再继续执行。在Java中,握手通常使用wait()和notify()方法实现。

然而,有时候会遇到一个问题:已经将握手入队(即调用了wait()方法),但是却无法再次将握手入队(即再次调用wait()方法)。这是因为调用wait()方法后,线程会释放对象锁,并且进入等待队列,直到被通知(即调用notify()方法)后再次获取对象锁。如果没有正确地通知等待线程,那么这个线程就会一直处于等待状态,无法再次入队。

以下是一个例子:

public class HandshakeExample {
    private boolean isReady = false;

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

    public synchronized void ready() {
        isReady = true;
        notify();
    }
}

该例子中,等待方法waitForReady()和通知方法ready()使用了同步关键字synchronized,确保同一时刻只有一个线程能够访问它们。在等待方法中,当isReady为false时,线程会调用wait()方法,释放对象锁并且进入等待队列。在通知方法中,当isReady被设置为true时,线程会调用notify()方法,通知等待线程重新竞争对象锁。

但是,如果通知方法先于等待方法被调用,那么等待线程就会一直处于等待状态,无法再次入队。例如:

HandshakeExample example = new HandshakeExample();

Thread waitingThread = new Thread(() -> {
    try {
        example.waitForReady();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

Thread notifyingThread = new Thread(() -> {
    example.ready();
});

notifyingThread.start();
waitingThread.start();

在这个例子中,通知线程先运行,将isReady设置为true并调用notify()方法。但是此时等待线程还没有开始运行,无法接收到通知。等待线程开始运行后,由于isReady已经为true,它会跳过while循环中的wait()方法,继续向下执行。由于没有正确的通知等待线程,等待线程就会一直处于等待状态,无法再次入队。

如果需要避免这个问题,可以使用一个volatile变量表示是否已经被通知过,或者使用Lock和Condition等更高级的同步机制,确保等待和通知的正确顺序。

参考链接: