Приостановить и возобновить поток в Java не работает

Я хотел применить потоки приостановки / возобновления, используя соответственно wait () / notify (). Я неоднократно пытался решить эту проблему, но не мог, поэтому, пожалуйста, помогите мне и объясните, почему notify (); не делает поток счетчика запускаемым:

public class Suspend {
boolean isSuspend = false;
int counter = 0;

synchronized public void suspend() {    
    isSuspend = true;
    System.out.println("The counter was suspended!");
}

synchronized public void resume() {
    isSuspend = false;
    System.out.println("The counter was resumed :)");
    notify();
}

public static void main(String[] args) {
    Thread.currentThread().setName("Main Thread");
    Suspend suspend = new Suspend();

    Thread counterThread = new Thread(new Runnable() {
        synchronized public void run() {
            while(!suspend.isSuspend) {
                System.out.println(suspend.counter++);
                try { Thread.sleep(1000); }
                catch (InterruptedException e) {}
            }
            try {
                while(suspend.isSuspend)
                    wait();
                }
            catch (InterruptedException e) {}
        }
    }, "Counter Thread");

    Thread suspendResumeThread = new Thread(new Runnable() {
        synchronized public void run() {
            while(true) {
                try {
                    Thread.sleep(5000);
                    suspend.suspend();
                    Thread.sleep(5000);
                    suspend.resume();
                } catch (InterruptedException e) {}
            }
        }
    }, "Suspend/Resume Thread");

    counterThread.start();
    suspendResumeThread.start();
}

}

Результат выглядит следующим образом: 0 1 2 3 4 The counter was suspended! The counter was resumed :) The counter was suspended! The counter was resumed :) ... and so on.

boolean isSuspend = false;, вероятно, должен быть энергозависимым или использовать вместо него AtomicBoolean
MadProgrammer 31.07.2018 00:01

Ваш первый поток ждет одну секунду, поэтому он напечатает 5 раз, прежде чем второй приостановит «блокировку», так что цикл первого потока прервется. Поскольку вы просто вызываете wait () после notify (), код будет возобновлен, но не будет кода для выполнения после, правильным будет вызвать wait () внутри цикла while и изменить его на while (true) с некоторым условием прерывания внутри.

Marcos Vasconcelos 31.07.2018 00:05

@MadProgrammer Спасибо за ваш комментарий, я пробовал как volatile, так и AtomicBoolean, но, к сожалению, это не работает.

Mohammed Tamimi 31.07.2018 00:31

@MarcosVasconcelos Спасибо за ваш комментарий, я пробовал следующее, но это не работает: while (true) {try {if (! Suspend.isSuspend) {System.out.println (suspend.counter ++); попробуйте {Thread.sleep (1000); } catch (InterruptedException e) {}} еще ждать (); } catch (InterruptedException e) {}}

Mohammed Tamimi 31.07.2018 00:41
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
266
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Взгляните на counterThread, пока он заканчивается при первом изменении флага isSuspend.

Думаю, вам нужно что-то вроде этого:

public class Suspend {
volatile boolean isSuspend = false;
int counter = 0;

synchronized public void suspend() {    
    isSuspend = true;
    System.out.println("The counter was suspended!");
}

synchronized public void resume() {
    isSuspend = false;
    System.out.println("The counter was resumed :)");
    notify();
}

public static void main(String[] args) {
    Thread.currentThread().setName("Main Thread");
    Suspend suspend = new Suspend();

    Thread counterThread = new Thread(new Runnable() {
        synchronized public void run() {
            while(true){
                while(!suspend.isSuspend) {
                    System.out.println(suspend.counter++);
                    try { Thread.sleep(1000); }
                    catch (InterruptedException e) {}
                }
                try {
                    while(suspend.isSuspend)
                        wait();
                }catch (InterruptedException e) {}
                }
             }
         }
    }, "Counter Thread");

    Thread suspendResumeThread = new Thread(new Runnable() {
        synchronized public void run() {
            while(true) {
                try {
                    Thread.sleep(5000);
                    suspend.suspend();
                    Thread.sleep(5000);
                    suspend.resume();
                } catch (InterruptedException e) {}
            }
        }
    }, "Suspend/Resume Thread");

    counterThread.start();
    suspendResumeThread.start();
}

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

Обновлено: я вставил неправильный код, извините

Спасибо за это важное замечание: ** вам также нужно использовать ключевое слово volatile для общих переменных **. Но ваш код не работает, и поток счетчика на этом не заканчивается. Согласно отладчику, статус counterThread - «ожидает: приостановить $ 1 (id = 19)».

Mohammed Tamimi 31.07.2018 00:53

Правда, я не заметил отсутствия объекта synchronized on suspend, но в любом случае вам нужно дополнительное while (true)

Frighi 31.07.2018 01:12
Ответ принят как подходящий

Проблема в этих строках:

while (suspend.isSuspend)
    wait();
}

в вашем counterThread Runnable.

Вы ждете на Runnable, а не на объекте suspend

Вам нужно выполнить синхронизацию на suspend и вызвать wait () на suspend:

synchronized (suspend) {
    while (suspend.isSuspend)
        suspend.wait();
    }
}

Кроме того, ваши методы run не нуждаются в синхронизации.

Большое спасибо, мистер Йоханнес Кун, действительно, ваш код верен на 100%.

Mohammed Tamimi 31.07.2018 01:04

Цикл whileдолжен находиться внутри синхронизированного блока или это не потокобезопасный. Вся суть wait() в том, что это атомарная операция, но только при удержании блокировки.

VGR 31.07.2018 15:50

Собственно, если suspend.isSuspended - это volatile, то синхронизировать его не нужно.

Johannes Kuhn 01.08.2018 00:27

Другие вопросы по теме