как я могу заставить поток спать некоторое время, а затем снова начать работать?


У меня есть следующий код:

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 2

9 ответов:

В этом коде отсутствует какой-либо цикл.

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

  1. Простой (и наивный) способ решить эту проблему-обернуть блок try-catch в бесконечный цикл (while(true) { ... }). Таким образом, после того, как поток закончит спать, он будет вернитесь к началу цикла и снова обработайте все задачи.

  2. Однако это не идеально, так как остановить поток практически невозможно. Лучший подход-объявить логическое поле (например, boolean running = true;) и изменить цикл на while(running). Таким образом, у вас есть способ заставить поток завершиться (например, предоставить метод, который устанавливает running в false.) Увидеть Солнце почему нити.остановите() устаревшую статью для более подробного объяснения этого.

  3. И делает шаг назад., возможно, вы пытаетесь сделать это на слишком низком уровне. Сон и планирование не являютсяна самом деле частью работы вашего 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 и так далее.