Почему моя реализация потоков, использующая ожидание и уведомление, заставляет мою программу не заканчиваться sh? - PullRequest
0 голосов
/ 02 мая 2020

Я все еще новичок в потоках, и я работал над простой программой, которая должна использовать два потока, которые оба увеличивают общий "счетчик" (интерфейс, реализованный классом "SychronizedCounter"). Они оба должны делать это установленное количество раз и всегда в повторяющейся последовательности (например, 01010101 .... (числа, обозначающие идентификатор потока (пользовательский заданный идентификатор, хранящийся в переменной)).

Я просто вставлю здесь важный код:

public class SynchronizedCounter implements Counter {

int count = 0;

public void increment() {
    synchronized (this) {
        count++;
    }
}

public int value() {
    synchronized (this) {
        return count;
    }       
}

}

А вот метод запуска потоков, работающих с экземпляром этого счетчика (будет два из этих потоков):

public void run() {

    synchronized (counter) { 
        for (int i = 0; i < numIterations; i++) {

            counter.increment();
            counter.notifyAll();

            if (id == 0) {
                while (counter.value() % 2 != 0) {
                    try {
                        counter.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            else {
                while (counter.value() % 2 != 1) {
                    try {
                        counter.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

         //IF I PLACE THE TWO CODE LINES HERE, THE PROGRAM WORKS!

        }
    }
}

Теперь у меня есть несколько вопросов, касающихся этого примера кода и партиций кода в целом:

  1. Две строки кода counter.increment (); counter.notifyAll (); вызывают мои программа работает бесконечно, если они размещены так, как они указаны выше. При отладке я даже видел потоки, пытающиеся вызвать wait и запускающие в InterruptedException, если две строки кода размещены, как указано выше. Однако, если я помещу их в конце (где комментарий), программа выполняется просто отлично. Почему? В чем здесь разница?

  2. Я заметил, что вызовы "уведомлять" всегда выполняются на е ин кода блока. Это почему? Опять же, если я сделаю это в моем примере кода, моя программа будет работать нормально. Есть ли соединение?

  3. Если бы я поместил синхронизированный блок в метод run () после заголовка для l oop, чтобы весь синхронизированный блок находился в пределах для l oop, а не для синхронизированного блока для l oop, это что-нибудь изменило бы?

Я очень благодарен за любую помощь!

...