2

我通常看到两种方法来实现一个守护进程,它做一些工作并进入睡眠并再次醒来。

  1. while(flag) 方法,其中 flag 为 true,如果我们想停止守护程序,则由其他类设置为 false。

    while(flag){
       //do something
       Thread.sleep(10000l);
    }
    
  2. 使用固定延迟使用 ScheduledThreadPoolExecutor 进行调度。

IMO,第二种方法更清洁且易于测试。有人可以比较这两种方法。第一种方法会导致任何内存问题吗?

谢谢

4

2 回答 2

3

第一种方法会导致任何内存问题吗?

不,最大的问题是管理flag变量的可见性。每当我看到有人建议这种方法时,我都会立即投反对票。该类Thread出于某种原因封装了中断标志的概念。

于 2013-02-21T09:58:15.050 回答
2

推荐方法 2)。

方法一对底层线程系统(尤其是在 UNIX 上)的随机唤醒不稳健,您还需要实现自己的错误处理

方法二允许您从底层抽象Thread并使用Runnableor Callable

此外,方法 1) 存在时钟漂移问题,即您的任务需要非零时间来执行,因此它不会每十秒执行一次。实际上,ScheduledExecutorService它将每秒安排一次执行,或者,如果需要,以十秒为间隔。

方法 2) 提供了一种简单的方法来安排线程在一段时间内做某事,然后按照javadoc中的示例将其杀死。

最后,ExecutorSevice关闭自定义线程要容易得多,只需调用executorService.shutdown()然后executorService.awaitTermination()等待最后一个任务完成即可。

您可能要注意的一件事是 javadoc 中的这个 gem -“如果任务的任何执行遇到异常,则后续执行将被抑制”。这意味着要么你必须非常小心try/catchCallable要么你需要继承它ScheduledExecutorService(取自 javadoc):

public class MyScheduledExecutor extends ScheduledThreadPoolExecutor {

    public MyScheduledExecutor(int corePoolSize) {
        super(corePoolSize);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t == null && r instanceof Future<?>) {
            try {
                Object result = ((Future<?>) r).get();
            } catch (CancellationException ce) {
                t = ce;
            } catch (ExecutionException ee) {
                t = ee.getCause();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt(); // ignore/reset
            }
        }
        if (t != null) {
            System.out.println(t);
        }
    }
}
于 2013-02-21T09:57:17.587 回答