📅  最后修改于: 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等更高级的同步机制,确保等待和通知的正确顺序。
参考链接: