难道另一个线程中的notify()是否可能在一个线程中的wait()之前被调用?我正在发生。
客户端从目标请求值,然后等待结果变量RV。如果目标是客户端本身,则用正确的结果更新RV,然后在另一个线程中对RV调用notify()。
class EMU {
ResultVar RV;
Address my_address;
ResultVar findValue(String key) {
String tgt = findTarget(key);
sendRequest(tgt, key);
synchronized(RV) {
RV.wait();
}
return RV;
}
Runnable Server = new Runnable() {
public void run() {
//code to receive connections. Assume object of type Request is read from the stream.
Request r = (Request) ois.readObject();
if(r.requesterAddr.compareTo(my_address) == 0) {
String val = findVal(key);
RV.putVal(val);
synchronized(RV){
RV.notify();
}
}
}
};
}
问题是,在请求者自己完成所有“联网”(在上面的示例中为sendReqest)之前,结果已在结果变量中更新。当请求者线程现在调用wait()时,该程序不会继续,因为已经调用了notify。
我们如何预防呢?
synchronized (results) {
while (!results.hasResults()) {
// no results yet; wait for them
try {
results.wait();
} catch (InterruptedException ie) { /* ignore */ }
}
}
使第一个线程获得对Future的访问权,并让第二个线程运行FutureTask,所有这些工作都将为您处理。您还可以免费获得超时支持。
class EMU{
ResultVar RV;
Address my_address;
volatile boolean condition = true;
ResultVar findValue(String key){
String tgt = findTarget(key);
sendRequest(tgt, key);
synchronized(RV){
while(condition == true)
{
RV.wait();
}
}
return RV;
}
Runnable Server = new Runnable(){
public void run(){
//code to receive connections. Assume object of type Request is read from the stream.
Request r = (Request) ois.readObject();
if(r.requesterAddr.compareTo(my_address) == 0){
String val = findVal(key);
RV.putVal(val);
synchronized(RV){
condition = false;
RV.notify();
}
}
}
};
public static void main(String[] args) throws Exception {
Object RV = new Object();
new Thread() {
@Override
public void run() {
synchronized (RV) {
RV.notify();
}
}
}.start();
Thread.sleep(1_000);
synchronized (RV) {
RV.wait();
}
}
从理论上讲,此方法永远不会结束,程序也永远不会退出。如果这是一个僵局,那将是一个争执。
我的解决方案是创建第二个锁:
public static void main(String[] args) throws Exception { Object RV = new Object(); Object lock = new Object(); new Thread() { @Override public void run() { synchronized (lock) { lock.wait(); } synchronized (RV) { RV.notify(); } } }.start(); Thread.sleep(1_000); synchronized (RV) { synchronized (lock) { lock.notify(); } RV.wait(); } }
让主线程在等待一秒钟的同时检查线程在做什么:
自定义线程将首先加入
synchronized(lock)
块。然后,锁将使自定义线程等待。
- 1秒后,主线程正在加入RV同步。
- 该锁将得到通知,并使自定义线程继续工作。
- 自定义线程离开
synchronized(lock)
块。- 主线程将RV等待锁定。
- 自定义线程通知RV锁继续。