我一般看到两种方法来实现守护进程,它可以完成一些工作并进入睡眠状态并再次唤醒。
while(flag)接近flag为true,如果我们想要停止守护进程,则由其他类设置为false。
while(flag){
//do something
Thread.sleep(10000l);
}
使用ScheduledThreadPoolExecutor使用固定延迟进行调度。
IMO,第二种方法更清洁,更容易测试。有人可以比较这两种方法。首先可以解决任何内存问题吗?
由于
答案 0 :(得分:3)
第一种方法可以导致任何内存问题吗?
没有。最大的问题是管理flag
变量的可见性。每当我看到有人建议这种方法时,我立即投票。由于某种原因,Thread
类封装了中断标志的概念。
答案 1 :(得分:2)
方法2)被推荐。
方法一对于底层线程系统的随机觉醒(特别是在UNIX上)并不健壮,而且你需要实现自己的错误处理
方法二允许您从基础Thread
中抽象出来并使用Runnable
或Callable
。
此外,方法1)存在时钟漂移问题,即您的任务需要非零时间执行,因此每隔十秒不执行一次。 ScheduledExecutorService
实际上会每秒安排一次执行,或者,如果需要,会以十秒的间隔安排执行。
方法2)提供了一种简单的方法来安排线程在一段时间内执行某些操作并按照javadoc中的示例将其终止。
最后,ExecutorSevice
更容易关闭自定义线程,只需调用executorService.shutdown()
然后executorService.awaitTermination()
等待上一个任务完成。
< / p>
您可能需要注意的一件事是来自javadoc的这个gem - “如果任务的任何执行遇到异常,后续执行都会被抑制”。这意味着您必须非常小心try/catch
中的Callable
,或者您需要对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);
}
}
}