Подтвердить что ты не робот

Как запустить/остановить/перезапустить поток в Java?

Мне очень трудно найти способ запуска, остановки и перезапуска потока в Java.

В частности, у меня есть класс Task (в настоящее время реализует Runnable) в файле Task.java. Мое основное приложение должно иметь возможность ЗАПУСТИТЬ эту задачу в потоке, STOP (убить) поток, когда это необходимо, а иногда KILL и RESTART поток...

Моя первая попытка заключалась в ExecutorService, но я не могу найти способ перезапустить задачу. Когда я использую .shutdownnow(), любой будущий вызов .execute() терпит неудачу, потому что ExecutorService - это "выключение"...

Итак, как я мог это сделать?

4b9b3361

Ответ 1

Как только поток остановится, его нельзя перезапустить. Однако нет ничего, что мешает вам создавать и запускать новый поток.

Вариант 1: Создайте новый поток, а не пытайтесь перезапустить.

Вариант 2: Вместо того, чтобы остановить поток, попросите его подождать, а затем, когда он получит уведомление, вы можете позволить ему снова выполнить работу. Таким образом, поток никогда не останавливается и никогда не будет перезагружен.

Изменить на основе комментария:

Чтобы "убить" поток, вы можете сделать что-то вроде следующего.

yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop

Ответ 2

Невозможно завершить поток, если код, выполняющийся в этом потоке, не проверяет и не разрешает завершение.

Вы сказали: "К сожалению, я должен убить/перезапустить его... У меня нет полного контроля над содержимым потока, и для моей ситуации он требует перезагрузки"

Если содержимое потока не позволяет завершить его exectuion, вы не можете завершить этот поток.

В вашем сообщении вы сказали: "Моя первая попытка была с ExecutorService, но я не могу найти способ перезапустить задачу. Когда я использую .shutdownnow()..."

Если вы посмотрите на источник "shutdownnow", он просто запускает и прерывает текущие потоки. Это не остановит их выполнение, если код в этих потоках не проверяет, был ли он отключен и, если это так, останавливает выполнение. Поэтому shutdownnow, вероятно, не делает то, что вы думаете.

Позвольте мне проиллюстрировать, что я имею в виду, когда говорю, что содержимое потока должно разрешить конец этого потока:

myExecutor.execute(new Runnable() {
 public void run() {
  while (true) {
    System.out.println("running");
  }
 }
 });
myExecutor.shutdownnow();

Этот поток будет продолжать работать вечно, даже если вызывается shutdownnow, потому что он никогда не проверяет, завершено ли оно или нет. Однако этот поток отключится:

myExecutor.execute(new Runnable() {
 public void run() {
  while (!Thread.interrupted()) {
    System.out.println("running");
  }
 }
 });
myExecutor.shutdownnow();

Так как этот поток проверяет, было ли оно прервано/выключено/завершено.

Итак, если вам нужен поток, который вы можете отключить, вам нужно убедиться, что он проверяет, прервано ли оно. Если вам нужен поток, который вы можете "выключить" и "перезапустить", вы можете сделать runnable, который может принимать новые задачи, как было упомянуто ранее.

Почему вы не можете закрыть запущенный поток? Ну, я на самом деле солгал, вы можете назвать "yourThread.stop()", но почему это плохая идея? Этот поток может быть синхронизирован (или другой критический раздел, но мы ограничимся настройками, защищенными синхронным ключевым словом здесь) в разделе кода, когда вы его остановите. синхронизирующие блоки должны выполняться в их entirity и только одним потоком, прежде чем к нему будет обращаться какой-либо другой поток. Если вы остановите поток в середине блока синхронизации, защита, установленная блоком синхронизации, окажется недействительной, и ваша программа попадет в неизвестное состояние. Разработчики делают вещи в синхронизирующих блоках, чтобы синхронизировать вещи, если вы используете threadInstance.stop(), вы уничтожаете значение синхронизации, что разработчик этого кода пытался выполнить и как разработчик этого кода ожидал, что его синхронизированные блоки будут ведут себя.

Ответ 3

Обзор java.lang.Thread.

Чтобы начать или перезапустить (как только поток остановлен, вы не можете перезапустить тот же поток, но это не имеет значения, просто создайте новый экземпляр Thread):

// Create your Runnable instance
Task task = new Task(...);

// Start a thread and run your Runnable
Thread t = new Thread(task);

Чтобы остановить его, попробуйте метод на вашем экземпляре Task, который устанавливает флаг для указания методу run для выхода; возврат из run завершает поток. Если ваш код вызова должен знать, что поток действительно остановился, прежде чем он вернется, вы можете использовать join:

// Tell Task to stop
task.setStopFlag(true);

// Wait for it to do so
t.join();

Что касается перезапуска: даже если Thread не может быть перезапущен, вы можете повторно использовать свой экземпляр Runnable с новым потоком, если он имеет состояние и что вы хотите сохранить; это приходит к одному и тому же. Просто убедитесь, что ваш Runnable предназначен для разрешения нескольких вызовов run.

Ответ 4

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

Эти две статьи Swing Worker и Concurrency может помочь вам определить наилучшее решение вашей проблемы.

Ответ 5

Как указано Taylor L, вы не можете просто "остановить" поток (путем вызова простого метода) из-за того, что он может оставить вашу систему в неустойчивом состоянии, поскольку поток внешнего вызова может не знать, что такое в вашей нити.

С учетом сказанного лучший способ "остановить" поток - следить за тем, чтобы поток следил за собой и чтобы он знал и понимал, когда он должен остановиться.

Ответ 6

Есть разница между приостановкой потока и остановкой/убийством. Если вы остановитесь, вы хотите убить поток, тогда перезапуск просто означает создание нового потока и запуск.

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

Вы можете увидеть немного больше: http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

Могу ли я спросить, почему вы хотите убить поток и перезапустить его? Почему бы просто не дождаться, пока его услуги снова понадобятся? Для этой цели Java имеет механизмы синхронизации. Поток будет спать, пока контроллер не уведомит его о продолжении выполнения.

Ответ 7

Если ваша задача выполняет какое-то действие в цикле, есть способ приостановить/перезапустить обработку, но я думаю, что это должно быть вне того, что предлагает API Thread. Если это единственный процесс, я не знаю, как приостановить/перезапустить, не запускаясь в API, который устарел или больше не разрешен.

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

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

Чтобы навсегда остановить поток, я бы использовал обычный API или оставил флаг в Задаче и установщик для флага (что-то вроде stopImmediately). Когда цикл обнаружил истинное значение для этого флага, он прекращает обработку и завершает метод выполнения.

Ответ 8

Иногда, когда был запущен Thread и он загружал динамический класс с понижением, который обрабатывает с большим количеством Thread/currentThread sleep при игнорировании прерывания Exception catch (es), одного прерывания может быть недостаточно, чтобы полностью завершить выполнение.

В этом случае мы можем предоставить эти прерывания на основе петли:

while(th.isAlive()){
    log.trace("Still processing Internally; Sending Interrupt;");
    th.interrupt();
    try {
        Thread.currentThread().sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Ответ 9

You can start a thread like:

    Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //Do you task
                    }catch (Exception ex){
                        ex.printStackTrace();}
                }
            });
thread.start();

To stop a Thread:

   thread.join();//it will kill you thread

   //if you want to know whether your thread is alive or dead you can use
System.out.println("Thread is "+thread.isAlive());

Желательно создать новый поток, а не перезапустить его.

Ответ 10

Я полностью не согласен с требованием "вы не можете остановить" поток ". Это близорукий взгляд на тернистый вопрос. Почему?

Регулярно проверяя, что прерванный флаг на самом деле является ничем иным, как другой формой ожидания, с трудным решением "когда проверять флаг и как часто". Может быть очень уродливым или невозможным ответить. В потоке класса также есть метод "stop (Throwable throwable)", который, к сожалению, устарел, что я глубоко не одобряю. Учитывая метод run() с его телом в try-catch-finally-statement: Почему все нормально, что любой оператор (изнутри тела) может выкинуть любое проверенное или неконтролируемое исключение, в то время как вызов остановки (новый MyRuntimeException()) извне не может? Неужели это так неожиданно извне? Тогда как насчет повторных неожиданных RuntimeExceptions, которые редко пойманы, поскольку они часто неизвестны? В конце, catch-clauses должны иметь дело с исключением - будь то изнутри или извне. И окончательный блок может привести в порядок. Надеюсь, люди снова подумают над этой проблемой дизайна.

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