簡體   English   中英

如何在不獲取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?

我知道有人問過有關在同步塊中更改鎖的問題,但是在多線程套接字編程的客戶端中,我的類中有一個狀態枚舉,每當我想要更改它時,我都會得到鎖並進行更改。 同時,另一個線程正在等待(它也獲得了相同的鎖,並且在到達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()放在最后。

第三個概念是notify()和notifyAll()之間的區別。 第一個只喚醒一個線程。 如果數據為空,並且您喚醒了一個想要刪除某些內容的線程,那么將導致死鎖。 如果您將全部喚醒,則所有人將檢查條件是否滿足並嘗試繼續。

這是另一個匹配更多代碼的示例:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM