NotifyAll удаляет ожидание из цикла без проверки условия? - PullRequest
0 голосов
/ 08 января 2019
public class ShareResource {

private int n = 0;

public synchronized void p() throws InterruptedException {
    while (n > 0) {
    wait();
    }
    n++;
}

public synchronized void r() {
  n = 0;
  notifyAll();
}

}

Если бы я запустил два потока с этим ресурсом, и они оба находятся в wait (), и я вызвал метод r () в ресурсе, это разбудило бы оба потока без проверки условия? Будет ли код читаться до конца метода в обоих потоках? В одно и то же время?

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Оба ожидающих потока получают уведомление. Обе ожидающие темы просыпаются внутри цикла. Оба должны проверить условие, чтобы выйти из цикла. Но один из ожидающих потоков пойдет первым и захлопнет дверь другого.

Когда ожидающий поток получает уведомление, он все еще находится в методе ожидания, он не может покинуть метод ожидания, пока не получит блокировку. (Помните, что ожидание находится внутри синхронизированного метода, и поток снял блокировку на объекте ShareResource, когда он начал ждать.) Конечно, только один поток может получить блокировку одновременно.

Из двух уведомленных потоков первый, кто получит блокировку, выйдет из метода ожидания, затем проверит условие цикла. Он находит, что n равно 0, и может выйти из цикла. Тогда поток увеличивает n. Все это происходит при удерживаемой блокировке, поэтому никакие другие потоки не могут вмешиваться.

Все это время второй поток был заблокирован; он был разбужен тем же уведомлением, что и первый поток, но не смог получить блокировку. Как только первый поток вышел из метода p, сняв блокировку, второй поток может взять блокировку и выйти из метода ожидания. В этот момент он проверяет условие цикла while, обнаруживает, что n больше 0 благодаря первому потоку, затем снова входит в метод wait и возвращается туда, где он начался.

Обратите внимание, что notifyAll, как правило, расточительно, потому что пробуждаются несколько потоков, но только один может добиться прогресса.

0 голосов
/ 08 января 2019

Будет ли код читаться до конца метода в обоих потоках? В то же время?

Нет и нет. Как работает notifyAll(), так это то, что каждый объект в конечном итоге выполняет свой код после пробуждения из wait(). Однако одновременно выполняется только один поток. Из-за этого после того, как один поток выходит из цикла через вызов r(), он увеличивает счетчик и, следовательно, не выпускает другой поток. Следовательно, до конца будет выполняться только один из потоков, но не в обоих.

Если бы я запустил два потока с этим ресурсом, и они оба находятся в wait (), и я вызвал метод r () в ресурсе, это разбудило бы оба потока без проверки условия?

Полагаю, вы имеете в виду, что цикл while завершается, когда вы имеете в виду «без проверки условия». Как видно выше, это не относится к обеим потокам.

TL; DR: notifyAll() позволяет одновременно выполнять только один поток, но в конечном итоге все они будут выполняться.

Источник: https://stackoverflow.com/a/37046/10869762

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...