我怎么能让线程睡了一会然后再开始工作?

时间:2012-05-16 10:13:47

标签: java multithreading thread-sleep

我有以下代码:

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 interrupted:null”。 谁能告诉我哪里出错了?

N.B。:我希望线程一直在工作,但是要抓住时段(比如说每5分钟一次)

9 个答案:

答案 0 :(得分:7)

你错过了那段代码中的任何循环。

似乎线程实际上正在做你告诉它要做的事情:它运行所有任务,然后睡了一会儿 - 然后就没有更多的工作要做了,所以退出了。有几种方法可以按照复杂性和正确性的升序来解决这个问题:

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

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

  3. 再向后退一步,你可能会试图在太低的水平上做到这一点。睡眠和日程安排不是真正Runnable工作的一部分。我将采用的实际解决方案是去掉睡眠,以便你有一个Runnable实现来处理所有任务然后终止。然后我会创建一个ScheduledExecutorService,并将“vanilla”runnable提交给执行者 - 这样,执行者的工作就是定期运行任务。

  4. 从工程角度来看,最后的解决方案是理想的。你有一个只运行一次作业并退出的类 - 只要你想运行作业,它就可以在其他环境中使用,并且编写得非常好。您有一个执行程序服务,其任务是调度任意任务 - 同样,您将来可以将不同类型的RunnableCallable传递给它,它也将执行调度位。可能最好的部分是,你不必自己编写任何调度内容,但可以在标准库中使用一个专门为你做这一切的类(因此很可能占用大部分与本土的并发代码不同,错误已经解决了。)

答案 1 :(得分:1)

任务调度在Java中具有一流的支持,不要重新发明它。实际上,有两个实现:Timer(old-school)和ScheduledExecutorService(new)。阅读它们并设计你的应用程序。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您需要将睡眠置于无限循环中(或者在您想睡觉时指定一些指定为静止的条件)。截至目前,在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());
        }
    }
}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

你可以把代码放在一个循环中。(可能是一段时间)

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 :(得分:0)

将线程置于其他人在此处提到的循环中。

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

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

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

答案 7 :(得分:0)

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 :(得分:0)

您可以尝试ScheduledExecutorServiceJavadoc)。 我们是scheduleAtFixedRate,其中:

  

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