Як убити 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()
працює, хоча Oracle каже, що він не повинен працювати, якщо interrupt()
цього не відбувається. Цікаво, як змусити це працювати і уникати використання застарілого методу.
Як правило, ви не ..
Ви просите перервати все, що він робить, використовуючи Thread.interrupt () (javadoc посилання)
Хороше пояснення того, чому тут у javadoc (посилання на техно-техніку java)
interrupt()
викликається метод? Основне питання пов'язане з генерацією журналу для кожного нового потоку.
У Java потоки не вбиваються, але зупинка потоку робиться спільно . Потік пропонується завершити, і потік може вимикатися витончено.
Часто використовується volatile boolean
поле, яке поток періодично перевіряє та припиняє, коли воно встановлюється на відповідне значення.
Я б не використовував a, boolean
щоб перевірити, чи повинна нитка закінчуватися . Якщо ви використовуєте volatile
як модифікатор поля, це буде працювати надійно, але якщо ваш код стає складнішим, оскільки натомість використовуються інші способи блокування всередині while
циклу, може статися, що ваш код не припиняється взагалі або, принаймні, триває довше, ніж ви може захотіти.
Деякі методи блокування бібліотеки підтримують переривання.
Кожна нитка має статус перерваного булевого прапора, і вам слід скористатися нею. Її можна реалізувати так:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Вихідний код адаптований з Java Concurrency in Practice . Оскільки 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. Так, дзвінок тривоги безпеки дзвонить скрізь, але це частина програми.) У цьому нещасному випадку, перш за все, ви просто сподіваєтесь, запитуючи сценаріїв сценаріїв поважати якийсь булевий сигнал запуску / не запуску. Ваша єдина гідна безпечна помилка - викликати метод зупинки на потоці, якщо, скажімо, він працює довше, ніж деякий час очікування.
Але це просто "пристойно", і не абсолютно, тому що код може зафіксувати помилку 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”);
Як правило, ви не вбиваєте, не зупиняєте або не перериваєте нитку (або перевіряєте, чи вона перервана ()), але нехай вона припиняється природним шляхом.
Це просто. Ви можете використовувати будь-який цикл разом із (мінливою) булевою змінною всередині методу 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;
}
"Вбити нитку" - це не правильне словосполучення. Ось один із способів ми можемо реалізувати витончене завершення / вихід потоку за заповітом:
Виконання, яке я використав:
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);
}
}
};
}
}