Как вы убиваете нить в Java?

Как ты убиваешь java.lang.Thread на яве?

17 ответов

Решение

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

Они рекомендуют использовать переменную общего доступа в качестве флага, который просит фоновый поток остановиться. Затем эта переменная может быть установлена ​​другим объектом, запрашивающим завершение потока.

Как правило, вы не..

Вы просите его прервать все, что он делает, используя Thread.interrupt() (ссылка на Javadoc)

Хорошее объяснение почему в javadoc здесь (ссылка на технику java)

В 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, чтобы "убить" поток.

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

  1. Thread.stop () остановит поток, если это разрешит менеджер безопасности.
  2. Thread.stop () опасен. Сказав это, если вы работаете в среде JEE и не можете контролировать вызываемый код, это может быть необходимо.
  3. Вы никогда не должны останавливать остановку рабочего потока контейнера. Если вы хотите запустить код, который имеет тенденцию зависать, (осторожно) запустите новый поток демона и следите за ним, убивая при необходимости.
  4. stop () создает новую ошибку ThreadDeath в вызывающем потоке, а затем приводит к тому, что эта ошибка применяется к целевому потоку. Поэтому трассировка стека, как правило, ничего не стоит.
  5. В JRE 6 stop () проверяет диспетчер безопасности, а затем вызывает stop1(), которая вызывает stop0(). stop0() - это нативный код.

Есть способ, как вы можете это сделать. Но если вам пришлось использовать его, либо вы плохой программист, либо вы используете код, написанный плохими программистами. Итак, вы должны подумать о том, чтобы перестать быть плохим программистом или перестать использовать этот плохой код. Это решение только для ситуаций, когда ДРУГОГО НЕТ.

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(),

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

Все это, и он может выполнять обработку ответов, которая может сильно загружать процессор. И вы, как разработчик, не можете даже остановить это, потому что вы не можете бросить if (Thread.currentThread().isInterrupted()) строки во всем коде.

Так что невозможность принудительно остановить поток это странно.

Вопрос довольно расплывчатый. Если вы имели в виду "как мне написать программу, чтобы поток прекратил работать, когда я этого захочу", тогда могут пригодиться другие ответы. Но если вы имели в виду "у меня аварийная ситуация с сервером, которую я не могу перезапустить прямо сейчас, и мне просто нужен конкретный поток, чтобы умереть, что бы ни случилось", то вам нужен инструмент вмешательства, соответствующий инструментам мониторинга, таким как jstack,

Для этого я создал jkillthread. Смотрите инструкции по его использованию.

Конечно, есть случай, когда вы запускаете какой-то не полностью доверенный код. (Лично я имею это, позволяя загруженным сценариям выполняться в моей среде Java. Да, повсюду звучит сигнал тревоги, но это часть приложения.) В этом печальном случае вы, прежде всего, надеетесь, спрашивая авторов сценариев. уважать какой-то логический сигнал "запустить / не запустить". Единственный достойный отказоустойчивый метод - это вызвать метод stop в потоке, если, скажем, он работает дольше, чем некоторое время ожидания.

Но это просто "прилично" и не абсолютно, потому что код может перехватить ошибку ThreadDeath (или любое исключение, которое вы явно выбросили), и не перебрасывать ее, как предполагается, что это делает джентльменский поток. Итак, суть в том, что AFAIA не является абсолютной отказоустойчивостью.

"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");

    }

}

Нет способа изящно убить нить.

Вы можете попытаться прервать поток, одна из общих стратегий состоит в том, чтобы использовать ядовитую таблетку, чтобы сообщить потоку, чтобы он остановился

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”);

http://anandsekar.github.io/cancel-support-for-threads/

Обычно вы не убиваете, не останавливаете и не прерываете поток (или не проверяете, прерван ли он ()), но позволяете ему завершаться естественным образом.

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

Таким образом, вы грациозно убиваете нить:) .

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

Существует два основных правильных решения для завершений контролируемых потоков:

  • Использование общего изменчивого флага
  • Использование пары методов Thread.interrupt() и Thread.interrupted().

Хорошее и подробное объяснение проблем, связанных с прерыванием резких потоков, а также примеры неправильных и правильных решений для завершения контролируемых потоков можно найти здесь:

https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads

Вот несколько хороших прочтений на эту тему:

Что вы делаете с InterruptedException?

Отключение темы

Я не получил прерывание для работы в 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;
 }

Thread.stop устарел, так как же остановить поток в java?

Всегда используйте метод прерывания и будущее, чтобы запросить отмену

  1. Когда задача реагирует на сигнал прерывания, например, метод блокировки очереди.
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);
}

  1. Когда задача не отвечает на сигнал прерывания. Предположим, что задача выполняет ввод-вывод сокета, который не реагирует на сигнал прерывания, и, таким образом, использование вышеуказанного подхода не прерывает задачу, время ожидания будет истекло в будущем, но отмена в блоке finally не будет иметь никакого эффекта, поток будет продолжать прослушивать сокет. Мы можем закрыть сокет или вызвать метод закрытия при подключении, если это реализовано пулом.
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);
                }
            }

        };
    }
}

После 15 с лишним лет разработки на Java я хочу сказать миру одну вещь.

Устаревший Thread.stop()и вся священная битва против его использования - это просто очередная вредная привычка или конструктивный недостаток, к сожалению, ставший реальностью... (например, хочу поговорить о Serializableинтерфейс?)

Битва сосредоточена на том факте, что уничтожение потока может оставить объект в несогласованном состоянии. Так что? Добро пожаловать в многопоточное программирование. Вы программист, и вам нужно знать, что вы делаете, и да... уничтожение потока может оставить объект в несогласованном состоянии. Если вы беспокоитесь об этом, используйте и пусть поток изящно завершит работу; но есть МНОЖЕСТВО моментов, когда нет причин для беспокойства.

Но нет.. если вы наберете thread.stop()вас, скорее всего, убьют все люди, которые смотрят/комментируют/используют ваш код. Таким образом, вы должны использовать flag, вызов interrupt(), место if(!flag)вокруг вашего кода, потому что вы вообще не зацикливаетесь, и, наконец , молитесь , чтобы сторонняя библиотека, которую вы используете для выполнения внешнего вызова, была написана правильно и не обрабатывала InterruptExceptionнеправильно.

Другие вопросы по тегам