2

我有以下代码:

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 分钟一次)

4

9 回答 9

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”提交给执行器——这样执行器的工作就是定期运行任务。

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

于 2012-05-16T10:17:26.350 回答
1

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

于 2012-05-16T10:21:08.757 回答
0

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

于 2012-05-16T10:16:49.260 回答
0

您需要将睡眠置于无限循环中(或在某些条件下指定您想要睡眠的时间)。到目前为止,在 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());
        }
    }
}
于 2012-05-16T10:16:52.703 回答
0

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

于 2012-05-16T10:17:43.510 回答
0

您可以将代码放入循环中。(可能是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);
}

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

于 2012-05-16T10:17:50.940 回答
0

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

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

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

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

于 2012-05-16T10:20:05.047 回答
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 (从您需要停止线程执行任务的任何地方)

于 2012-05-16T10:20:05.883 回答
0

你可以试试ScheduledExecutorServiceJavadoc)。而我们是scheduleAtFixedRate,其中:

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

于 2012-05-16T10:22:25.243 回答