Как я могу изменить блокировку, полученную в синхронизированном блоке, изменить ее и notifyAll () без получения java.lang.IllegalMonitorStateException? - PullRequest
0 голосов
/ 26 июня 2018

Я знаю, что задавались вопросы об изменении блокировки в синхронизированном блоке, но в моей клиентской части программирования многопоточных сокетов у меня есть перечисление статуса в моем классе, и каждый раз, когда я хочу его изменить, я получаю блокировку и выполняю командуперемены.В то же время другой поток ожидает (он также получает ту же блокировку и после достижения метода wait отпускает его) наблюдать изменения после того, как поток чейнджера вносит свои изменения и вызывает notifyAll ().Теперь, если я хочу уведомитьAll () об объекте (я имею в виду перечисление состояния), который изменяется, я получаю 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();
    }

1 Ответ

0 голосов
/ 29 июня 2018

В этом коде есть ошибка:

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

Вам разрешено только notifyAll () для заблокированного вами объекта.Но одна строка над вами заменила объект другим.Это действительно плохая идея, чтобы изменить объект блокировки.Обычно вы будете использовать «это» или вы используете частный объект.

Я бы предложил следующее решение:

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 вместо if ().

Вторая концепция известна по уведомлению и возобновлению.Можно уведомить () и сохранить блокировку.Таким образом, вам не нужно ставить notify () в конце.

Третья концепция - это различие между notify () и notifyAll ().Первый пробуждает только одну нить.Если данные пусты, и вы просыпаетесь в потоке, который хочет что-то удалить, чтобы была тупиковая блокировка.Если вы разбудите всех, все проверит, выполнено ли условие, и попытайтесь продолжить.

Вот еще один пример, который больше соответствует вашему коду:

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