【问题标题】:how can i make a thread sleep for a while and then start working again?我怎样才能让线程休眠一段时间然后重新开始工作?
【发布时间】:2012-05-16 10:13:46
【问题描述】:

我有以下代码:

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());
     }
}

我正在尝试让线程休眠特定时间“FREQUENCY”,然后再次工作。当我在eclipse中执行这段代码时,线程只工作一次,然后什么也没有发生,进程终止。如果我从语句中删除注释:t.start(),我会得到“FetcherThread 中断:null”。 谁能告诉我哪里出错了?

注意:我希望线程一直在工作,但会按周期获取(比如每 5 分钟一次)

【问题讨论】:

  • 如果您取消注释 t.start(),您会收到编译器错误并且无法运行它。

标签: java multithreading thread-sleep


【解决方案1】:

您在该代码中缺少任何类型的循环。

似乎线程实际上正在执行您告诉它执行的操作:它运行所有任务,然后休眠一段时间 - 然后它没有更多工作要做,因此退出。有几种方法可以解决这个问题,按照复杂性和正确性的升序排列:

  1. 解决这个问题的简单(和天真的)方法是将 try-catch 块包装在无限循环中 (while(true) { ... })。这样线程完成休眠后,会循环回到顶部,重新处理所有的任务。

  2. 但这并不理想,因为基本上不可能停止线程。更好的方法是声明一个布尔字段(例如boolean running = true;),并将循环更改为while(running)。这样,您就有办法让线程终止(例如,公开一个将 running 设置为 false 的方法。)请参阅 Sun 的 Why is Thread.stop() deprecated 文章以获得对此的详细说明。

  3. 再退一步,您可能会尝试在太低的级别上执行此操作。睡觉和安排时间并不是您Runnable 工作的真正的一部分。我会采用的实际解决方案是去掉睡眠,这样你就有一个 Runnable 实现来处理所有任务然后终止。然后我会创建一个ScheduledExecutorService,并将可运行的“vanilla”提交给执行程序——这样执行程序的工作就是定期运行任务。

从工程角度来看,最后一种解决方案是理想的。您有一个只运行一次作业并退出的类 - 只要您想运行作业,就可以在其他上下文中使用它,并且组合得很好。你有一个执行器服务,它的工作是调度任意任务——同样,你可以在未来将不同类型的RunnableCallable 传递给它,它也会执行调度位。可能最好的部分是,您不必自己编写任何调度内容,而是可以使用标准库中专门为您完成这一切的类(因此可能有大部分与本地并发代码不同,错误已经解决)。

【讨论】:

【解决方案2】:

任务调度在 Java 中具有一流的支持,不要重新发明它。事实上,有 两个 实现:Timer(老派)和ScheduledExecutorService(新)。阅读它们并围绕它们设计您的应用程序。

【讨论】:

    【解决方案3】:

    尝试在不同的线程上执行任务。

    【讨论】:

      【解决方案4】:

      您需要某种循环来重复您的工作流程。控制流如何返回到获取部分?

      【讨论】:

        【解决方案5】:

        您可以将代码放入循环中。(可能是while)

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

        在您的情况下发生了什么,它运行任务循环然后休眠一段时间并退出线程。

        【讨论】:

          【解决方案6】:

          像其他人在这里提到的那样,将线程置于循环中。

          我想补充一点,多次调用 Thread.start 是非法的,这就是你得到异常的原因。

          如果您想生成多个线程,请为每个要启动的线程创建一个 Thread 对象。

          http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#start()

          【讨论】:

            【解决方案7】:
            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(从您需要停止线程执行任务的任何地方)

            【讨论】:

              【解决方案8】:

              您需要将睡眠置于无限循环中(或在某些条件下指定您想要睡眠的时间)。到目前为止,在 run 方法结束时调用了 sleep 方法,并且您观察到的行为是正确的。 以下演示代码将在休眠一秒钟后在控制台上打印“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());
                      }
                  }
              }
              

              【讨论】:

                【解决方案9】:

                你可以试试ScheduledExecutorService (Javadoc)。 而我们是scheduleAtFixedRate,其中:

                创建并执行一个周期性动作,该动作在给定的初始延迟后首先启用,然后在给定的周期内启用;也就是说,执行将在 initialDelay 之后开始,然后是 initialDelay+period,然后是 initialDelay + 2 * period,依此类推。

                【讨论】:

                  猜你喜欢
                  • 2021-01-18
                  • 2013-08-29
                  • 1970-01-01
                  • 2019-06-02
                  • 2022-08-20
                  • 2013-12-22
                  • 2021-01-22
                  • 2011-04-26
                  • 1970-01-01
                  相关资源
                  最近更新 更多