我如何更改我在同步块中获得的锁,更改它并在不获取 java.lang.IllegalMonitorStateException 的情况下进行 notifyAll()?

how can I change the lock I have aquired in a synchronized block, change it, and notifyAll() without getting java.lang.IllegalMonitorStateException?

我知道有人问过关于更改同步块中的锁的问题,但在我的多线程套接字编程客户端中,我的 class 中有一个状态枚举,每次我想更改它时我得到锁并进行更改。与此同时,另一个线程正在等待(它也获得相同的锁,并且在到达 wait 方法后释放它)以观察更改器线程进行更改并调用 notifyAll() 之后的更改。 现在,如果我想在一个已更改的对象(我的意思是状态枚举)上使用 notifyAll(),我会得到 java.lang.IllegalMonitorStateException! 我考虑过获取另一个共享的最终对象作为我的锁,但这样也许线程仍然能够操作状态枚举。什么是最好的方法? 任何答案将不胜感激。 这是我的代码的一部分:

这是更换线程:

synchronized (client.getStatus()) {
    client.setStatus(ClientState.successfulRegistration);
    client.getStatus().notifyAll()
}

这是等待线程:

synchronized (client.getStatus()){
    try {
            client.getStatus().wait();
            System.out.println("signMeIn notified");
            ClientState result = client.getStatus();
            System.out.println(result);
            if(result.toString().equalsIgnoreCase("successfulSignIn") )
                //do sth
        } catch (InterruptedException e) {
            e.printStackTrace();
    }

这段代码有错误:

synchronized (client.getStatus()) {
    client.setStatus(ClientState.successfulRegistration);
    client.getStatus().notifyAll()
}

您只能对您锁定的对象使用 notifyAll()。但是你上面的一行用不同的对象替换了对象。更改锁定对象是一个非常糟糕的主意。通常您会使用 "this" 或使用私有对象。

我建议采用以下解决方案:

public synchronized void setStatus(T status) {}
public synchronized T getStatus() {}

wait() 和 notifyAll() 方法仅在您等待某个条件并想要释放锁时才需要。举个例子:

public synchronized void add(T element) {
   while(full) {
     wait();
   }
   data.add(element);
   notifyAll();
}

public synchronized T remove() {
    while(empty) {
      wait();
    }
    T item = data.getAndremove();
    notifyAll();
    return item;
}

在这个例子中有很多隐藏的概念。首先,您需要一个 while 循环来等待。因为如果您等待并收到通知,您将回到准备 运行 队列中。但是您不知道条件是否仍然成立,因此您必须重新检查条件。这就是为什么您使用 while 循环而不是 if() 的原因。

第二个概念是notify-and-resume。可以通知()并保持锁定。所以你不必把 notify() 放在最后。

第三个概念是notify()和notifyAll()的区别。第一个只唤醒一个线程。如果数据为空并且您唤醒了一个想要删除某些内容的线程,那么就会出现死锁。如果你wake-up all,all会检查是否满足条件并尝试继续。

这是另一个与您的代码更匹配的示例:

public synchronized void doSth() {
   while(client.getStatus.equals("WAIT") {
        wait();
   }
   System.out.println("Status isn't wait");
}