Остановка потока и синхронизация - PullRequest
1 голос
/ 25 января 2011

Я читаю книгу, в которой сказано не использовать такой код:

private volatile Thread myThread;

....

myThread.stop();

Вместо этого следует использовать:

if (myThread != null ) {

 Thread dummy = myThread;

 myThread = null;

 dummy.interrupt();


}

К сожалению, предмет более не проработан ... Может кто-нибудь объяснить мне это?

Ответы [ 7 ]

3 голосов
/ 25 января 2011

stop() устарело. Никогда никогда и никогда не используйте stop(). Вместо этого вы можете использовать java concurrency .

С Javadoc :

Этот метод небезопасен. Остановка потока с помощью Thread.stop приводит к тому, что он разблокирует все заблокированные мониторы (как естественное следствие непроверенного исключения ThreadDeath, распространяющегося вверх по стеку). Если какой-либо из объектов, ранее защищенных этими мониторами, находился в несогласованном состоянии, поврежденные объекты становятся видимыми для других потоков, что может привести к произвольному поведению. Многие варианты использования stop должны быть заменены кодом, который просто изменяет некоторую переменную, чтобы указать, что целевой поток должен прекратить работу. Целевой поток должен регулярно проверять эту переменную и упорядоченно возвращаться из своего метода run, если переменная указывает, что она должна прекратить работу. Если целевой поток ожидает длительные периоды (например, для переменной условия), для прерывания ожидания следует использовать метод прерывания.

Взгляните на Параллелизм Java на практике глава 7 (Отмена и завершение работы)

3 голосов
/ 25 января 2011

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

public class MyRunnable extends Runnable {
    public volatile boolean keepRunning = true;
    public void run() {
        while (keepRunning) {
            ... // do what you have to do
        }
    }
}

Как только вы решите закончить, вам просто нужно установить для переменной keepRunning значение false. Ваша тема будет тогда: - закончить оставшиеся шаги - прекратить

Таким образом, вы завершаете свою работу контролируемым образом и не используете небезопасный stop() метод.

1 голос
/ 31 марта 2013

В дополнение к тому, что предложил @Paweloque (что является идеальным способом), есть другая альтернатива использованию stop (), предложенная здесь

Неправильный путь:

Предположим, ваш апплет содержит следующие методы запуска, остановки и запуска:

private Thread blinker;

public void start() {
    blinker = new Thread(this);
    blinker.start();
}

public void stop() {
    blinker.stop();  // UNSAFE!
}

public void run() {
    Thread thisThread = Thread.currentThread();
    while (true) {
        try {
            thisThread.sleep(interval);
        } catch (InterruptedException e){
        }
        repaint();
    }
}

Правильный путь

Вы можете избежать использования Thread.stop, заменив методы апплета stop и run на: частный энергозависимый мигающий поток;

public void stop() {
    blinker = null;
}

public void run() {
    Thread thisThread = Thread.currentThread();
    while (blinker == thisThread) {
        try {
            thisThread.sleep(interval);
        } catch (InterruptedException e){
        }
        repaint();
    }
}
1 голос
/ 25 января 2011

Каждый дал отличную информацию о том, почему бы не вызвать Thread.stop ().

Комментарий Сергея исправил неверную информацию, которую я дал об обработке interrupt (). Я предпочитаю использовать сигнальный флаг, как в ответе lewap. Как сказал Сергей, interrupt () предназначен для пробуждения потока, который находится в заблокированной операции. Если ваш поток не вызывает никаких операций блокировки, тогда interrupt () фактически не завершит поток. Тем не менее, ваш поток может вызвать isInterrupted (), чтобы узнать, было ли вызвано прерывание (в основном, сигнальный флаг).

Возвращаясь к примеру с вашей книгой, мне это не нравится.

if (myThread != null ) {

    Thread dummy = myThread;

    myThread = null;

    dummy.interrupt();

}

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

Авторы книги могут подумать о том, чтобы не допустить одновременной попытки других потоков прервать один и тот же поток, но этот код прерывания не является потокобезопасным (операция «проверить, если ноль и задано значение ноль» не является атомарной), поэтому написание фиктивного задания - это мутная вода без дополнительной безопасности.

1 голос
/ 25 января 2011

Несмотря на то, что Thread.stop устарел. Также полезно знать, что с Thread.stop вы можете обойти проверку исключений, проверенную copmiler. Например,

public void doSomething(){
    Thread.currentThread().stop(new IOException());
}

Это вызовет IOException. IOException является проверенным проверенным исключением, и компилятор обычно заставляет клиента перехватывать или позволять методу бросить его. Здесь doSomething выбрасывает непроверенное IOException

1 голос
/ 25 января 2011

Thread.stop устарел и не должен использоваться (дополнительная информация здесь ).

Пример кода, по-видимому, аннулирует ссылку на «myThread», а затем сигнализирует о ее прерывании.,Предполагая, что «myThread» является единственной ссылкой на ваш поток, и код, выполняющийся в потоке, обрабатывает запросы на прерывания должным образом (и не игнорирует их), поток завершится и будет иметь право на сборку мусора, когда «if (myThread! = Null)"кодовый блок завершен.

1 голос
/ 25 января 2011

Thread.stop () is устарело . Не используйте это. Зачем? Чтение Примитивный поток Java устарел

...