нить не прерывается - PullRequest
1 голос
/ 03 апреля 2020

Я пытаюсь поработать над известными столовыми философами, и он довольно закончен, но мне довольно трудно пытаться прерывать потоки.

так что, как вы знаете, в этой задаче у нас есть 5 потоков ( философы) и пользователь установили время эксперимента, в которое эксперимент закончится.

Стоит заметить, что я посмотрел несколько ответов на StackOverflow.

Первый из @Konrad Reiche Как ты убиваешь тему в Java? / Ссылка на Stackoverflow

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

Вторым является Прерывание потока () не прерывает поток / ссылка Stackoverflow

, но на самом деле ничего не помогло!.

Я постараюсь предоставить необходимый код, и я надеюсь, что кто-то просто укажет на мои ошибки. класс Philosopher опубликован c и расширяет Thread!.

1) Первая попытка: (может быть отвергнута профессором, если он не хочет, чтобы мы использовали volatile boolean в качестве флага!)

при использовании логического выражения volatile, как это работает:

private volatile boolean isNotStopped=true;

@Override
public void stopPhilosopher() {
    System.out.printf("\n%s will stop.\n",selfPhilosopher.getName());
    selfPhilosopher.interrupt();
    isNotStopped=false;
}


@Override
public void run() {
    while (isNotStopped){//selfPhilosopher is a thread equals to this!.
        try {
                think();
                eat();
        } catch (InterruptedException e) {//somehow this was never triggered!.
            System.out.printf("%s was interrupted.\n",selfPhilosopher.getName());
        }finally {//in the finally block i always get RUNNER, FALSE
            System.out.printf("the %s is %s and is interrupted %b.\n", selfPhilosopher.getName(),selfPhilosopher.getState(), selfPhilosopher.isInterrupted());
        }
    }
}

[ОБНОВЛЕНИЕ] при второй попытке: [РАБОТАЕТ]

замена selfPhilosopher.isInterrupted() на Thread.currentThread().isInterrupted() не имела никакого значения как selfPhilosopher=this;

пока я получал "остановлюсь" от метода stopPhilosopher(), но потоки, похоже, зомби продолжают возвращаться к жизни :(

из-за того, что Я вполне убежден мнением @Konrad Reiche из первой предоставленной ссылки и ответом @Nathan Hughes. Я буду придерживаться использования логического флага, предоставленного java isInterrupted() вместо использования изменчивый флаг.

@Override
public void stopPhilosopher() {
    System.out.printf("\n%s will stop.\n",selfPhilosopher.getName());
    selfPhilosopher.interrupt();

}

@Override
public void run() {
    while (!selfPhilosopher.isInterrupted()){//selfPhilosopher is a thread equals to this!.
        try {
                think();
                eat();
        } catch (InterruptedException e) {//somehow this was never triggered!.Now it works.
            System.out.printf("%s was interrupted from catch clause!..\n",selfPhilosopher.getName());
            selfPhilosopher.interrupt();
        }
    }
}

ВЫХОД:

 Philosopher2 in seat nr: 2 was interrupted from catch clause!..

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

Когда создается исключение InterruptedException, флаг прерывания сбрасывается. Это означает, что следующая проверка, которую сделает ваш l oop, покажет, что поток не прерван, и поток продолжит работать. Это то, что вы видите, когда ваш блок finally печатает false для флага прерывания.

Это описано в API do c для метода сна :

InterruptedException - если какой-либо поток прервал текущий поток. Прерванное состояние текущего потока очищается при возникновении этого исключения.

Добавьте эту строку в блок, где вы перехватываете исключение InterruptedException:

Thread.currentThread().interrupt();  // restores interrupt flag
0 голосов
/ 02 мая 2020

Прежде всего: я предпочитаю volatile логический флаг вместо isInterrupted(). Это ясно, кратко и идиоматически установлено. Необходимая структура для isInterrupted() зависит больше от деталей (например, try / catch в вашем случае, потому что кажется, что Thread.sleep (или что-то подобное) объявляет InterruptedException).

Поскольку try / catch InterruptedException в вашем примере находится в пределах while-l oop, прерывание используется, и его необходимо повторно отправить на selfPhilosopher (что выглядит немного сомнительно). Чтобы избежать этого, поместите while-l oop в окружающий try-catch:

try {
    while (!selfPhilosopher.isInterrupted()) {
        think();
        eat();
    } 
} catch (InterruptedException e) {
    System.out.printf("%s was interrupted from catch clause!..\n",selfPhilosopher.getName());
    // not necessary anymore: selfPhilosopher.interrupt();
}

Изменяемый логический флаг не нужно повторно отправлять, и его можно использовать в обоих созвездиях (также при окружении try / catch). как в пределах try).

Дополнительно: предположим, что ваш класс реализует Runnable и не расширяет Thread, тогда вам также необходимо позаботиться об установке selfPhilosopher в начале run (и нигде еще).

...