Thread.stop() - устарел
Почему Thread.stop()
не рекомендуется в Java? На их сайте я вижу следующее:
Почему
Thread.stop
осуждается?Потому что это небезопасно. Остановка потока приводит к тому, что он разблокирует все заблокированные мониторы. (Мониторы разблокированы как
ThreadDeath
Исключение распространяется вверх по стеку.) Если какой-либо из объектов, ранее защищенных этими мониторами, находился в несогласованном состоянии, другие потоки теперь могут просматривать эти объекты в несогласованном состоянии. Такие объекты, как говорят, повреждены. Когда потоки работают с поврежденными объектами, это может привести к произвольному поведению. Это поведение может быть тонким и его трудно обнаружить, или оно может быть выражено. В отличие от других непроверенных исключений,ThreadDeath
молча убивает темы; таким образом, пользователь не предупреждает, что его программа может быть повреждена. Коррупция может проявиться в любое время после фактического ущерба, даже часов или дней в будущем.
Я не понимаю, что они имеют в виду под "мониторами". Несмотря на это, мой вопрос, если Thread.stop()
не должен быть вызван тогда, как должен быть остановлен поток Java?
6 ответов
Вы спрашивали:
Мой вопрос: если нет способа остановить поток в Java, то как остановить поток?
Ответ: В Java нет чистого, быстрого или надежного способа остановить поток.
Завершение нити не так просто. Работающий поток, часто называемый многими авторами как легкий процесс, имеет свой собственный стек и является хозяином своей собственной судьбы (ну, конечно, демоны). Может иметь собственные файлы и сокеты. Это может держать замки. Резкое завершение не всегда легко: непредсказуемые последствия могут возникнуть, если поток находится в процессе записи в файл и завершается до того, как завершить запись. Или как насчет замков монитора, удерживаемых нитью, когда она стреляет в голову?
Вместо этого потоки используют кооперативный механизм, называемый прерыванием. Это означает, что потоки могут только сигнализировать другим потокам об остановке, но не заставлять их останавливаться.
Чтобы остановить потоки в Java, мы полагаемся на кооперативный механизм, называемый прерыванием. Концепция очень проста. Чтобы остановить поток, все, что мы можем сделать, это доставить ему сигнал, то есть прервать его, запросив, чтобы поток остановился при следующей доступной возможности. Это все. Невозможно сказать, что может сделать поток приемника с сигналом: он может даже не потрудиться проверить сигнал; или еще хуже игнорировать это.
Источник: http://10kloc.wordpress.com/2013/03/03/java-multithreading-steeplechase-stopping-threads/
Когда ваш поток правильно обрабатывает прерывания, должна быть возможность немедленно прекратить его с использованием ExecutorService
интерфейс. Согласно документации Oracle, ExecutorService.shutdownNow()
метод, пытается остановить все активно выполняемые задачи, не дожидаясь их завершения. Однако нет никаких гарантий, кроме попыток приложить все усилия, чтобы остановить их. Вот пример кода:
class MyThread implements Runnable{
@Override
public void run() {
for (int i = 1; i < 10000000; i++)
try {
System.out.println(i + " ThreadID: " + Thread.currentThread().getId());
if (Thread.interrupted())
throw new InterruptedException();
} catch (InterruptedException e) {
return;
}
}
}
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new MyThread());
executor.submit(new MyThread());
executor.submit(new MyThread());
executor.shutdownNow();
Без прерывания каждая нить должна вывести сообщение на консоль 10000000 раз. executor.shutdownNow()
Метод мгновенно останавливает все три потока.
Правильный путь - использовать соединение. Вместо преждевременной остановки выполнения потока, join будет ждать завершения потока до перехода к следующему оператору.
Thread exampleThread = new Thread(){
public void run(){
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
//handle the exception
}
}
};
exampleThread.start();
exampleThread.join();
Здесь exampleThread.join() будет ожидать завершения выполнения exampleThread, прежде чем перейти к следующему оператору. Однако ответственность за то, чтобы поток завершил выполнение, лежит на программисте. По сути, нет способа остановить поток, но если вы спроектируете его правильно, вам не нужно останавливать поток.
Логика остановки потока должна обрабатываться в вашей реализации потока, чтобы вы были уверены, что все идет так, как вы хотите. Например, вы можете создатьcancel()
метод, изменяющий состояние потока, который проверяется циклически. Нравится:
class StoppableThread implements Runnable {
boolean isCancelled = false;
public void run() {
while (!isCancelled) {
System.out.println("Thread is running with all its might!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void cancel () {
isCancelled = true;
}
}
Из https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html:
В большинстве случаев использование stop должно быть заменено кодом, который просто изменяет некоторую переменную, чтобы указать, что целевой поток должен прекратить работу. Целевой поток должен регулярно проверять эту переменную и упорядоченно возвращаться из своего метода run, если переменная указывает, что она должна прекратить работу. Чтобы обеспечить быструю передачу стоп-запроса, переменная должна быть изменчивой (или доступ к переменной должен быть синхронизирован).
Потоки в Java интересны тем, что то, как вы их реализуете, зависит от цели программы, которую вы пишете. Если вы не ставите во главу угла эффективность своей программы,thread.join()
это метод, который используется для ожидания "завершения" выполнения потока Java. Обратите внимание, что он используется для ожидания потока Java, а не для остановки потока, и в этом случае мы можем предположить, что поток завершает выполнение после того, как он завершил выполнениеrun()
метод. Причина использованияthread.stop()
метод опасен, потому что мы не знаем, как планировщик заказал выполнение потока, и эта неопределенность весьма расстраивает, но мы должны смириться с этим. Допустим, вы используете этот метод, когда поток читает объекты из основной памяти. Это может привести к огромным накладным расходам, потому что планировщик теперь вынужден отдавать приоритет остановке этого потока и игнорировать другие потоки... Так что это одна из многих причин, почему использованиеthread.stop
следует обескураживать