Это хороший способ закрыть поток? - PullRequest
0 голосов
/ 21 марта 2010

У меня есть короткая версия вопроса:

  1. Я запускаю такую ​​тему: counter.start();, где counter - это тема.
  2. В момент, когда я хочу остановить поток, я делаю это: counter.interrupt()
  3. В своей ветке я периодически делаю эту проверку: Thread.interrupted(). Если он выдает true I return из потока и, как следствие, останавливается.

А вот некоторые детали, если необходимо:

Если вам нужны подробности, они здесь. Из изобретенной нити отправки я запускаю встречную нить следующим образом:

public static void start() {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            showGUI();
            counter.start();
        }
    });
}

где поток определяется так:

public static Thread counter = new Thread() {
    public void run() {
        for (int i=4; i>0; i=i-1) {
            updateGUI(i,label);
            try {Thread.sleep(1000);} catch(InterruptedException e) {};
        }
            // The time for the partner selection is over.
        SwingUtilities.invokeLater(new Runnable() {
                public void run() {    
                frame.remove(partnerSelectionPanel);
                frame.add(selectionFinishedPanel);
                frame.invalidate();
                frame.validate();
            }
        });
    }
};

Поток выполняет обратный отсчет в «первом» окне (показывает дом много времени осталось). Если ограничение по времени истекло, поток закрывает «первое» окно и генерирует новое. Я хочу изменить мою тему следующим образом:

public static Thread counter = new Thread() {
    public void run() {
        for (int i=4; i>0; i=i-1) {
            if (!Thread.interrupted()) {
                updateGUI(i,label);
            } else {
                return;
            }
            try {Thread.sleep(1000);} catch(InterruptedException e) {};
        }
        // The time for the partner selection is over.
        if (!Thread.interrupted()) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {    
                frame.remove(partnerSelectionPanel);
                frame.add(selectionFinishedPanel);
                frame.invalidate();
                frame.validate();
            }
        });
        } else {
            return;
        } 
    }
};

ДОБАВЛЕНО:

По некоторым причинам это не работает. У меня есть метод, который прерывает поток:

public static void partnerSelected() {
    System.out.println("The button is pressed!!!!");
    counter.interrupt();
}

Этот метод активируется при нажатии кнопки. Когда я нажимаю кнопку, я вижу соответствующий вывод в терминале (поэтому этот метод активирован, и он что-то делает). Но по ряду причин это не прерывает поток. Вот код для темы:

public static Thread counter = new Thread() {
    public void run() {
        for (int i=40; i>0; i=i-1) {
                if (Thread.interrupted()) {
                    System.out.println("Helloo!!!!!!!!!!!!!!!");
                    return;
                }
            updateGUI(i,label); 
            try {Thread.sleep(1000);} catch(InterruptedException e) {};
        }
            // The time for the partner selection is over.
            if (Thread.interrupted()) {
                System.out.println("Helloo!!!!!!!!!!!!!!!");
                return;
            }
        SwingUtilities.invokeLater(new Runnable() {
                public void run() {    
                frame.remove(partnerSelectionPanel);
                frame.add(selectionFinishedPanel);
                frame.invalidate();
                frame.validate();
            }
        });
    }
};

P.S. Я не вижу "Привет !!!!!!!!!!!!!" в терминале ...

Ответы [ 5 ]

5 голосов
/ 21 марта 2010

Довольно близко к правильной идее. Однако в вашем catch (InterruptedException) должно быть:

Thread.currentThread().interrupt();

, чтобы прерванный статус снова включался и не выполнял работу во втором блоке.


Отредактируйте, чтобы прояснить мою точку зрения (потому что редактирование ОП, кажется, пропустило мою начальную точку :-P): вы должны написать свой код так:

try {
    for (int = 40; i > 0; --i) {
        updateGUI(i, label);
        Thread.sleep(1000);
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();  // <-- THIS LINE IS IMPORTANT
}

Второе редактирование, чтобы объяснить, что делает прерывание. : -)

Когда вы вызываете thread.interrupt(), устанавливается флаг прерывания этого потока . Этот флаг ничего не делает сам по себе; это просто переменная. Причина этого заключается в том, что прерывание поддерживает то, что называется «совместное управление потоками», когда исполняемый код потока решает, что делать при прерывании (вместо того, чтобы принудительно завершать работу на месте).

Некоторые функции, встроенные в JDK, такие как Thread.sleep, или Object.wait, или Lock.lockInterruptibly, будут проверять флаг, а если он установлен, то выдает InterruptedException после снятия флажка.

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

Есть два способа проверить флаг:

  1. interrupted()
  2. isInterrupted()

Первый очищает прерванный флаг; второй нет. Вы должны решить, какая версия является «более правильной» для логики вашего приложения.

1 голос
/ 21 марта 2010

Ознакомьтесь с этой статьей из JavaSpecialists новостной рассылки, в которой рассказывается, как interrupt() темы и правильно управлять этим.

0 голосов
/ 21 марта 2010
  1. Считается, что для этой цели лучше использовать ( ссылка ) отдельную переменную (логическое значение isStopped).

  2. Предположим, что метод interrupted() изменяет значение с истинного на ложное, если ваш поток был прерван, то есть ::

System.out.println (Thread.interrupted()); //true</p> <p>System.out.println (Thread.interrupted()); //false

Альтернатива - isInterrupted() метод.

0 голосов
/ 21 марта 2010

Я бы хотел отредактировать и отметить, что сегодня я усвоил урок. Нет никакой причины для реализации логического значения, как я объясню в следующих двух параграфах; механизм прерываний делает это для меня. По какой-то причине я предположил, что «прерывание» останавливает поток, мертвый в его треках (я не знаю, что я думал, что тогда сделал Interrupted ()!).

Итак, вот пример того, чего не следует делать. Продолжайте использовать свою технику прерывания!

(пожалуйста, не отрицайте меня ...)


Я стараюсь избегать прерываний, но особенно, чтобы остановить поток. В вашем случае вы пытаетесь использовать interrupt () в качестве альтернативы stop (), которая устарела по уважительной причине. Все, что вам нужно сделать, это объявить логическое значение, которое представляет, должен ли поток прекратить считать, и заставить поток постоянно проверять это логическое значение. Затем, когда родительский поток готов к остановке счетчика, он должен установить для логического значения значение true (остановка), что приведет к остановке потока счетчика, как только он снова проверит значение.

В определении анонимного класса вашего потока Counter добавьте public volatile boolean shouldStop;. В начале run() установите shouldStop = false;. Затем замените все Thread.interrupted() на shouldStop (в ваших if утверждениях). Наконец, вместо того, чтобы звонить counter.interrupt(), просто скажите counter.shouldStop = true;. Вы можете дополнительно позвонить counter.join() сразу после установки shouldStop=true, если хотите убедиться, что счетчик остановлен, прежде чем продолжить.

0 голосов
/ 21 марта 2010

Да, это путь

...