Как вы убиваете java.lang.Thread
в Java?
ExecutorStatus
этого вопроса: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Как вы убиваете java.lang.Thread
в Java?
ExecutorStatus
этого вопроса: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Ответы:
Посмотрите эту ветку от Sun о том, почему они устарелиThread.stop()
. Подробно рассказывается о том, почему это был плохой метод, и что нужно сделать для безопасной остановки потоков в целом.
Они рекомендуют использовать общую переменную в качестве флага, который просит фоновый поток остановиться. Затем эта переменная может быть установлена другим объектом, запрашивающим завершение потока.
getConnection()
из java.sql.DriverManager
. Если проверка соединения занимает слишком много времени, я пытаюсь уничтожить соответствующий поток, вызвав Thread.interrupt()
его, но это никак не влияет на поток. Thread.stop()
Работает , однако, хотя оракул говорит , что это не должно работать , если interrupt()
нет. Интересно, как заставить это работать и избежать использования устаревшего метода.
Как правило, вы не ..
Вы просите его прервать все, что он делает, используя Thread.interrupt () (ссылка на Javadoc)
Хорошее объяснение того, почему в Javadoc здесь (ссылка Java Technote)
interrupt()
вызове метода? Основной вопрос связан с созданием журнала для каждой новой темы.
В Java потоки не уничтожаются, но остановка потока выполняется кооперативным способом . Поток просят прекратить, и затем поток может корректно завершиться.
Часто используется volatile boolean
поле, которое поток периодически проверяет и завершает, когда ему присваивается соответствующее значение.
Я не использовал бы, boolean
чтобы проверить, должен ли поток закончиться . Если вы используете volatile
в качестве модификатора поля, это будет работать надежно, но если ваш код становится более сложным, поскольку вместо этого используются другие методы блокировки внутри while
цикла, может случиться так, что ваш код вообще не завершится или по крайней мере займет больше времени, так как вы может хотеть.
Некоторые блокирующие библиотечные методы поддерживают прерывание.
Каждый поток уже имеет статус прерванного логического флага, и вы должны использовать его. Это может быть реализовано так:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Исходный код адаптирован из Java Concurrency на практике . Так как cancel()
метод общедоступен, вы можете позволить другому потоку вызывать этот метод так, как вам нужно.
Один из способов - установить переменную класса и использовать ее в качестве часового.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Установите внешнюю переменную класса, т.е. flag = true в приведенном выше примере. Установите значение false, чтобы «убить» поток.
volatile
чтобы убедиться, что он работает везде. Внутренний класс не является статическим, поэтому флаг должен иметь переменную экземпляра. Флаг должен быть очищен в методе доступа, чтобы можно было выполнять другие операции (например, прерывание). Название «флаг» не носит описательный характер.
Есть способ, как вы можете это сделать. Но если вам пришлось его использовать, либо вы плохой программист, либо вы используете код, написанный плохими программистами. Итак, вы должны подумать о том, чтобы перестать быть плохим программистом или перестать использовать этот плохой код. Это решение только для ситуаций, когда ДРУГОГО НЕТ.
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
Thread.stop
даже если она устарела.
Thread.stop
делает то же самое, но также проверяет доступ и разрешения. Использование Thread.stop
довольно очевидно, и я не помню причину, почему я использовал Thread.stop0
вместо этого. Может быть Thread.stop
, не работает для моего особого случая (Weblogic на Java 6). Или, может быть, потому что Thread.stop
устарела и вызывает предупреждение.
Я хочу добавить несколько замечаний, основанных на накопленных комментариях.
Thread.stop()
остановит поток, если менеджер безопасности это разрешит.Thread.stop()
опасный. Сказав это, если вы работаете в среде JEE и не можете контролировать вызываемый код, это может быть необходимо; см. Почему Thread.stop устарел?stop()
создает новую ThreadDeathError
ошибку в вызывающем потоке, а затем выбрасывает эту ошибку в целевой поток. Поэтому трассировка стека, как правило, ничего не стоит.stop()
проверяет диспетчер безопасности, а затем вызывает stop1()
эти вызовы stop0()
. stop0()
это нативный кодThread.stop()
не был удален (пока), но Thread.stop(Throwable)
был удален в Java 11. ( список рассылки , JDK-8204243 )Я бы проголосовал за Thread.stop()
.
Например, у вас длительная операция (например, сетевой запрос). Предположительно, вы ждете ответа, но это может занять некоторое время, и пользователь перешел на другой пользовательский интерфейс. Этот ожидающий поток теперь а) бесполезен; б) потенциальная проблема, потому что когда он получит результат, он совершенно бесполезен, и он вызовет обратные вызовы, которые могут привести к количеству ошибок.
Все это, и он может выполнять обработку ответов, которая может сильно загружать процессор. И вы, как разработчик, не можете даже остановить это, потому что вы не можете бросать if (Thread.currentThread().isInterrupted())
строки во всем коде.
Так что невозможность принудительно остановить поток это странно.
Thread.stop()
все равно не сможете безопасно позвонить . Вы не голосуете за Thread.stop()
, вы спрашиваете о каждом человеке, который выполняет все операции, которые могут занять много времени, чтобы сделать их безопасными для прерывания. И это может быть хорошей идеей, но это не имеет ничего общего с реализацией Thread.stop()
в качестве способа запроса безопасного аборта. У нас уже есть interrupt
для этого.
stop
.
Вопрос довольно расплывчатый. Если вы имели в виду «как мне написать программу, чтобы поток прекратил работать, когда я этого захочу», тогда могут пригодиться другие ответы. Но если вы имели в виду «у меня аварийная ситуация с сервером, которую я не могу перезапустить прямо сейчас, и мне просто нужен конкретный поток, чтобы умереть, что бы ни случилось», то вам нужен инструмент вмешательства, соответствующий инструментам мониторинга, подобным jstack
.
Для этого я создал jkillthread . Смотрите инструкции по его использованию.
Конечно, есть случай, когда вы запускаете какой-то не полностью доверенный код. (Лично я имею это, позволяя загруженным сценариям выполняться в моей среде Java. Да, повсюду звучит сигнал тревоги, но это часть приложения.) В этом печальном случае вы, прежде всего, надеетесь, спрашивая авторов сценариев. уважать какой-то логический сигнал «запустить / не запустить». Единственный достойный отказоустойчивый метод - это вызвать метод stop в потоке, если, скажем, он работает дольше, чем некоторое время ожидания.
Но это просто «прилично», и не абсолютно, потому что код может перехватить ошибку ThreadDeath (или любое исключение, которое вы явно выбросили), и не перебрасывать ее, как предполагается, что это делает джентльменский поток. Итак, суть в том, что AFAIA не является абсолютной отказоустойчивостью.
Нет способа изящно убить нить.
Вы можете попытаться прервать поток, одна из общих стратегий состоит в том, чтобы использовать ядовитую таблетку, чтобы сообщить потоку, чтобы он остановился
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
Обычно вы не убиваете, не останавливаете и не прерываете поток (или не проверяете, прерван ли он ()), но позволяете ему завершаться естественным образом.
Это просто. Вы можете использовать любой цикл вместе с (volatile) логической переменной внутри метода run () для управления деятельностью потока. Вы также можете вернуться из активного потока в основной поток, чтобы остановить его.
Таким образом, вы грациозно убиваете нить :).
Попытки внезапного завершения потока являются общепринятой плохой практикой программирования и свидетельством плохого дизайна приложения. Все потоки в многопоточном приложении явно и неявно совместно используют одно и то же состояние процесса и вынуждены взаимодействовать друг с другом, чтобы поддерживать его согласованность, иначе ваше приложение будет подвержено ошибкам, которые будет действительно трудно диагностировать. Таким образом, разработчик несет ответственность за обеспечение такой согласованности посредством тщательного и четкого проектирования приложения.
Существует два основных правильных решения для завершений контролируемых потоков:
Хорошее и подробное объяснение проблем, связанных с прерыванием резких потоков, а также примеры неправильных и правильных решений для завершения контролируемых потоков можно найти здесь:
Вот несколько хороших прочтений на эту тему:
Я не получил прерывание для работы в Android, поэтому я использовал этот метод, работает отлично:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
«Killing a thread» - не правильная фраза для использования. Вот один способ, которым мы можем реализовать изящное завершение / завершение потока по желанию:
Runnable, который я использовал:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
Класс запуска:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
Thread.stop устарел, так как мы можем остановить поток в Java?
Всегда используйте метод прерывания и будущее, чтобы запросить отмену
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}