我有以下代码:
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分钟一次)
答案 0 :(得分:7)
你错过了那段代码中的任何循环。
似乎线程实际上正在做你告诉它要做的事情:它运行所有任务,然后睡了一会儿 - 然后就没有更多的工作要做了,所以退出了。有几种方法可以按照复杂性和正确性的升序来解决这个问题:
解决此问题的简单(和天真)方法是将try-catch块包装在无限循环(while(true) { ... }
)中。这样,在线程完成休眠后,它将循环回到顶部并再次处理所有任务。
然而,这并不理想,因为基本上不可能停止线程。更好的方法是声明一个布尔字段(例如boolean running = true;
),并将循环更改为while(running)
。这样,您就可以使线程终止(例如,公开将running
设置为false
的方法。)请参阅Sun的Why is Thread.stop() deprecated文章,以获得更长的解释。
再向后退一步,你可能会试图在太低的水平上做到这一点。睡眠和日程安排不是真正的Runnable
工作的一部分。我将采用的实际解决方案是去掉睡眠,以便你有一个Runnable实现来处理所有任务然后终止。然后我会创建一个ScheduledExecutorService,并将“vanilla”runnable提交给执行者 - 这样,执行者的工作就是定期运行任务。
从工程角度来看,最后的解决方案是理想的。你有一个只运行一次作业并退出的类 - 只要你想运行作业,它就可以在其他环境中使用,并且编写得非常好。您有一个执行程序服务,其任务是调度任意任务 - 同样,您将来可以将不同类型的Runnable
或Callable
传递给它,它也将执行调度位。可能最好的部分是,你不必自己编写任何调度内容,但可以在标准库中使用一个专门为你做这一切的类(因此很可能占用大部分与本土的并发代码不同,错误已经解决了。)
答案 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)
您可以尝试ScheduledExecutorService
(Javadoc)。
我们是scheduleAtFixedRate
,其中:
创建并执行一个周期性操作,该操作在给定的初始延迟后首先启用,然后在给定的时间段内启用;执行将在initialDelay之后开始,然后是initialDelay + period,然后是initialDelay + 2 * period,依此类推。