Я хочу запустить поток в течение определенного промежутка времени. Если он не будет завершен в течение этого времени, я хочу либо убить его, либо выдать какое-то исключение, либо как-то обработать его. Как это можно сделать?
Как я понял из этого потока, один из способов сделать это - использовать TimerTask внутри метода run () потока .
Есть ли лучшие решения для этого?
РЕДАКТИРОВАТЬ: Добавление щедрости, как мне нужно более четкий ответ. Приведенный ниже код ExecutorService не решает мою проблему. Почему я должен спать () после выполнения (некоторый код - у меня нет никакого контроля над этим фрагментом кода)? Если код завершен и sleep () прерван, как это может быть timeOut?
Задача, которую нужно выполнить, не в моем контроле. Это может быть любой кусок кода. Проблема в том, что этот кусок кода может попасть в бесконечный цикл. Я не хочу, чтобы это случилось. Итак, я просто хочу запустить эту задачу в отдельном потоке. Родительский поток должен ждать, пока этот поток не завершится, и должен знать состояние задачи (т. Е. Истекло ли время или произошло какое-то исключение, или если оно выполнено успешно). Если задача входит в бесконечный цикл, мой родительский поток продолжает ждать бесконечно, что не является идеальной ситуацией.
источник
sleep()
была просто заглушка, чтобы представлять «долгосрочное задание». Просто замените его своим реальным заданием;)interrupt()
вызовы в ее потоке ... не все "блокирующие" вызовы делают, как я пытался указать в своем ответе. Специфика задачи, которую вы пытаетесь прервать, имеет огромное значение в подходе, который следует использовать. Дополнительная информация о задаче будет полезна.Ответы:
На самом деле лучше использовать
ExecutorService
вместоTimer
, вот SSCCE :Поиграйте немного с
timeout
аргументом вFuture#get()
методе, например, увеличьте его до 5, и вы увидите, что поток завершается. Вы можете перехватить таймаут вcatch (TimeoutException e)
блоке.Обновление: уточнить концептуальное недоразумение, то
sleep()
это не требуется. Он просто используется в целях SSCCE / демонстрации. Просто сделайте свою долгосрочную задачу прямо на местеsleep()
. Внутри вашей длительной задачи вы должны проверить, не прерывается ли поток следующим образом:источник
Thread.sleep(4000)
другим длительным оператором, и пример не сработает. Другими словами, этот пример будет работать, только еслиTask
он предназначен для пониманияThread.isInterrupted()
изменения статуса.Не существует 100% надежного способа сделать это для любой старой задачи. Задача должна быть написана с учетом этой способности.
Базовые библиотеки Java, такие как
ExecutorService
отмена асинхронных задачinterrupt()
вызовами в рабочем потоке. Так, например, если задача содержит какой-то цикл, вы должны проверять ее состояние прерывания на каждой итерации. Если задача выполняет операции ввода-вывода, они также должны быть прерываемыми, и их настройка может быть сложной. В любом случае имейте в виду, что код должен активно проверять наличие прерываний; установка прерывания не обязательно делает что-либо.Конечно, если ваша задача представляет собой какой-то простой цикл, вы можете просто проверять текущее время на каждой итерации и сдаваться по истечении указанного времени ожидания. В этом случае рабочий поток не нужен.
источник
execute()
Метод родительского интерфейса,Executor
может запустить задачу в вызывающем потоке. Нет аналогичного утверждения дляsubmit()
методовExecutorService
этого возвращаемогоFuture
экземпляра. Смысл службы заключается в том, что существуют рабочие потоки, которые необходимо очистить с помощью выключения, и что задачи выполняются асинхронно. Тем не менее, в контракте нет ничего, что говорило бы о том, чтоExecutorService
запрещено выполнять задачи в потоке отправки; эти гарантии исходят от API-интерфейсов реализации, таких какExecutors
фабрики.Рассмотрите возможность использования экземпляра ExecutorService . Оба
invokeAll()
иinvokeAny()
методы доступны сtimeout
параметром.Текущий поток будет блокироваться до тех пор, пока метод не завершится (не уверен, если это желательно), либо потому, что задача (и) выполнена нормально, либо истекло время ожидания. Вы можете проверить возвращенные
Future
(ие), чтобы определить, что произошло.источник
Предполагая, что код потока находится вне вашего контроля:
Из документации Java, упомянутой выше:
Нижняя граница:
Убедитесь, что все потоки могут быть прерваны, или же вам нужны специальные знания о потоке - например, наличие установленного флага. Может быть, вы можете потребовать, чтобы вам дали задачу вместе с кодом, необходимым для ее остановки - определите интерфейс с
stop()
методом. Вы также можете предупредить, когда вам не удалось остановить задачу.источник
BalusC сказал:
Но если вы замените
Thread.sleep(4000);
на,for (int i = 0; i < 5E8; i++) {}
то он не скомпилируется, потому что пустой цикл не генерируетInterruptedException
.И для того, чтобы поток был прерываемым, он должен бросить
InterruptedException
.Это кажется серьезной проблемой для меня. Я не понимаю, как адаптировать этот ответ для работы с общей долгосрочной задачей.
Отредактировано, чтобы добавить: я переосмыслил это как новый вопрос: [ прерывание потока через фиксированное время, должно ли оно генерировать InterruptedException? ]
источник
Я думаю, что вы должны взглянуть на правильные механизмы обработки параллелизма (потоки, работающие в бесконечные циклы, сами по себе не кажутся хорошими, кстати). Убедитесь, что вы прочитали немного о теме «убивать» или «остановить» темы .
То, что вы описываете, звучит очень похоже на «рандеву», так что вы можете взглянуть на CyclicBarrier .
Могут быть и другие конструкции (например, использующие CountDownLatch ), которые могут решить вашу проблему (один поток ожидает с тайм-аутом для защелки, другой должен отсчитывать защелку, если он выполнил свою работу, которая освободит ваш первый поток либо после тайм-аут или когда вызывается отсчет защелки).
Я обычно рекомендую две книги в этой области: параллельное программирование на Java и параллелизм на практике .
источник
Я создал вспомогательный класс только для этого некоторое время назад. Прекрасно работает:
Это называется так:
источник
Я отправляю вам фрагмент кода, который показывает способ решения проблемы. В качестве примера я читаю файл. Вы можете использовать этот метод для другой операции, но вам нужно реализовать метод kill (), чтобы основная операция была прервана.
Надеюсь, поможет
С уважением
источник
Вот мой действительно простой в использовании вспомогательный класс для запуска или вызова части кода Java :-)
Это основано на превосходном ответе от BalusC
источник
Следующий фрагмент запускает операцию в отдельном потоке, затем ждет до 10 секунд, пока операция не завершится. Если операция не завершится вовремя, код попытается отменить операцию, а затем продолжить свой веселый путь. Даже если операция не может быть легко отменена, родительский поток не будет ожидать завершения дочернего потока.
getExecutorService()
Метод может быть реализован несколькими способами. Если у вас нет особых требований, вы можете просто вызватьExecutors.newCachedThreadPool()
пул потоков без верхнего предела количества потоков.источник
SomeClass
иFuture
?Одна вещь, о которой я не упомянул, это то, что убийство потоков - это, как правило, плохая идея. Существуют методы для того, чтобы сделать потоковые методы полностью прерываемыми , но это отличается от простого уничтожения потока после истечения времени ожидания.
Риск того, что вы предлагаете, заключается в том, что вы, вероятно, не знаете, в каком состоянии будет поток, когда вы его убьете, поэтому вы рискуете ввести нестабильность. Лучшее решение состоит в том, чтобы убедиться, что ваш многопоточный код либо не зависает, либо будет хорошо отвечать на запрос прерывания.
источник
Отличный ответ от BalusC:
но просто добавлю, что само время ожидания не прерывает сам поток. даже если вы проверяете с помощью while (! Thread.interrupted ()) в своей задаче. если вы хотите убедиться, что поток остановлен, вы также должны убедиться в том, что future.cancel () вызывается при перехвате исключения тайм-аута.
источник
Я думаю, что ответ в основном зависит от самой задачи.
Если первый ответ - да, а второй - нет, вы можете сделать это так просто:
Если это не вариант, сузьте ваши требования или покажите какой-нибудь код.
источник
Я искал ExecutorService, который может прервать все тайм-ауты Runnable, выполненные им, но не нашел ни одного. Через несколько часов я создал один, как показано ниже. Этот класс может быть изменен для повышения надежности.
Использование:
источник
Теперь я сталкиваюсь с такой проблемой. Это происходит, чтобы декодировать изображение. Процесс декодирования занимает слишком много времени, чтобы экран оставался черным. l добавить контроллер времени: если время слишком велико, то всплывающее окно из текущего потока. Ниже приводится разница:
источник
У меня такая же проблема. Поэтому я пришел к такому простому решению.
Гарантирует, что если блок не будет выполнен в течение срока. процесс завершится и выдаст исключение.
пример :
источник
В решении, предоставленном BalusC , основной поток остается заблокированным в течение периода ожидания. Если у вас есть пул потоков с более чем одним потоком, вам потребуется то же количество дополнительных потоков, которые будут использовать блокирующий вызов Future.get (long timeout, TimeUnit unit) для ожидания и закрытия потока, если он превышает период времени ожидания.
Общее решение этой проблемы - создать декоратор ThreadPoolExecutor, который может добавить функцию тайм-аута. Этот класс Decorator должен создать столько потоков, сколько имеется в ThreadPoolExecutor, и все эти потоки следует использовать только для ожидания и закрытия ThreadPoolExecutor.
Универсальный класс должен быть реализован как показано ниже:
Вышеуказанный декоратор может быть использован как ниже:
источник