как я могу заставить поток спать некоторое время, а затем снова начать работать?
У меня есть следующий код:
public void run()
{
try
{
logger.info("Looking for new tasks to fetch... ");
// definitions ..
for(Task t: tasks)
{
logger.info(" Task " + t.getId() + " is being fetched ");
// processing ... fetching task info from db using some methods
}
Thread.sleep(FREQUENCY);
//t.start();
} catch (Exception e)
{
logger.info("FetcherThread interrupted: "+e.getMessage());
}
}
Я пытаюсь заставить поток спать в течение определенного времени "частоты", а затем снова работать. когда я выполняю этот код в eclipse, поток работает только один раз, а затем ничего не происходит и процесс завершается. Если я удалю комментарий из инструкции: t.start()
, я получу "fetcherthread interrupted: null".
Кто-нибудь может сказать мне, где я ошибаюсь?
N. B.: Я хочу, чтобы поток работал все время, но выбирал периоды (скажем, каждые 5 минуты)
9 ответов:
В этом коде отсутствует какой-либо цикл.
Похоже, что поток на самом деле делает то, что вы ему говорите: он выполняет все задачи, затем немного спит - затем у него больше нет работы, и поэтому он выходит. Существует несколько способов решить эту проблему в порядке возрастания сложности и правильности:
Простой (и наивный) способ решить эту проблему-обернуть блок try-catch в бесконечный цикл (
while(true) { ... }
). Таким образом, после того, как поток закончит спать, он будет вернитесь к началу цикла и снова обработайте все задачи.Однако это не идеально, так как остановить поток практически невозможно. Лучший подход-объявить логическое поле (например,
boolean running = true;
) и изменить цикл наwhile(running)
. Таким образом, у вас есть способ заставить поток завершиться (например, предоставить метод, который устанавливаетrunning
вfalse
.) Увидеть Солнце почему нити.остановите() устаревшую статью для более подробного объяснения этого.И делает шаг назад., возможно, вы пытаетесь сделать это на слишком низком уровне. Сон и планирование не являютсяна самом деле частью работы вашего
Runnable
. Фактическое решение, которое я бы принял, состоит в том, чтобы удалить спящий режим, чтобы у вас была запускаемая реализация, которая обрабатывает все задачи, а затем завершается. Затем я бы создалScheduledExecutorService и отправил бы исполнителю "vanilla" runnable - таким образом, задача исполнителя заключается в том, чтобы периодически запускать задачу.В последнее решение идеально с инженерной точки зрения. У вас есть класс, который просто запускает задание один раз и завершает его - это может быть использовано в других контекстах, когда вы хотите запустить задание, и составляется очень хорошо. У вас есть служба исполнителей, задача которой - планирование произвольных задач-опять же, вы можете передать ей различные типы
Runnable
илиCallable
в будущем, и она также будет выполнять планирование. И, возможно, самое лучшее, что вам не нужно писать никаких расписаний. набивайтесь сами, но можете использовать класс в стандартной библиотеке, который специально делает все это для вас (и поэтому, вероятно, большинство ошибок уже сглажено, в отличие от доморощенного кода параллелизма).
Планирование задач имеет первоклассную поддержку в Java,не изобретайте его. На самом деле, есть две реализации:
Timer
(старая школа) иScheduledExecutorService
(новая). Читайте о них и создавайте свое приложение вслух.
Вам нужен какой-то цикл, чтобы повторить свой рабочий процесс. Как поток управления должен вернуться к части извлечения?
Вы можете поместить код в цикл.( Может быть, пока)
while(condition) // you can make it while(true) if you want it to run infinitely. { for(Task t: tasks) { logger.info(" Task " + t.getId() + " is being fetched "); // processing ... fetching task info from db using some methods } Thread.sleep(FREQUENCY); }
Что происходит в вашем случае, это запуск цикла задач, затем спящий в течение некоторого времени и выход из потока.
Поместите нить в петлю, как другие упоминали здесь.
Я хотел бы добавить, что вызывающий поток.запуск более одного раза является незаконным, и именно поэтому вы получаете исключение.
Если вы хотите создать несколько потоков, создайте один объект потока для каждого потока, который вы хотите запустить.
См. http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#start()
public void run() { while (keepRunning) { try { logger.info("Looking for new tasks to fetch... "); // definitions .. for(Task t: tasks) { logger.info(" Task " + t.getId() + " is being fetched "); // processing ... fetching task info from db using some methods t.start(); } Thread.sleep(FREQUENCY); } catch (Exception e) { keepRunning = false; logger.info("FetcherThread interrupted: "+e.getMessage()); } } }
Добавьте вызов члена keepRunning к основному потоку и реализуйте метод доступа для установки его в false (оттуда, где вам нужно остановить поток от выполнения задач)
Вам нужно поместить сон в бесконечный цикл (или с некоторым условием, определяющим uptill, когда вы хотите спать). На данный момент метод sleep вызывается в конце метода run, и поведение, которое вы наблюдаете, является правильным. Следующий демонстрационный код выведет "Sleep" на консоль после секундного сна. Надеюсь, это поможет.
import java.util.concurrent.TimeUnit; public class Test implements Runnable { /** * @param args */ public static void main(String[] args) { Test t = new Test(); Thread thread = new Thread(t); thread.start(); } public void run() { try { // logger.info("Looking for new tasks to fetch... "); // definitions .. // for(Task t: tasks) // { // logger.info(" Task " + t.getId() + " is being fetched "); // // processing ... fetching task info from db using some methods // } while (true) { // your condition here TimeUnit.SECONDS.sleep(1); System.out.println("Sleep"); } // t.start(); } catch (Exception e) { // logger.info("FetcherThread interrupted: "+e.getMessage()); } } }
Вы могли бы попробовать
ScheduledExecutorService
(Javadoc ). А нас этоscheduleAtFixedRate
, которые:Создает и выполняет периодическое действие, которое включается сначала после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay+period, затем initialDelay + 2 * period и так далее.