当我通过调用ScheduledExecutorService.schedule()创建一个线程时,它在执行计划任务后永远不会终止。
例如,以下程序永不退出:
public static void main(String[] args) {
ScheduledFuture scheduledFuture =
Executors.newSingleThreadScheduledExecutor().schedule(new Callable() {
public Void call() {
doSomething();
return null;
}
}, 1, TimeUnit.SECONDS);
}
public static void doSomething() {
}
这是一个JDK错误,还是我错过了什么?
答案 0 :(得分:7)
计划任务正在执行或正在等待执行。
如果任务等待执行,future.cancel()
将阻止它被执行(取消(true)/取消(false))。
如果任务已在执行,future.cancel(false)
将无效。 future.cancel(true)
将中断正在执行该任务的线程。 这是否会产生任何影响取决于你,谁将实施该任务。根据实施,任务可能会也可能不会响应中断。
为了使您的任务响应取消,您必须实施doSomething()
,以便它能够响应中断。
基本上有两种方法可以做到这一点:
1.检查逻辑中的中断标志
public void doSomething(){
stuff();
//Don't use Thread.interrupt()
if(Thread.currentThread().isInterrupted()){
// We have an interruption request, possibly a cancel request
//Stop doing what you are doing and terminate.
return;
}
doLongRunningStuff();
}
您必须偶尔检查中断标志,如果中断,请停止正在进行的操作并返回。请务必使用Thread.isInterrupted()而不是Thread.interrupt()进行检查。
2.Act on Interrupted exception
public void doSomething(){
try{
stuff();
}catch(InterruptedException e){
// We have an interruption request, possibly a cancel request
// First, preserve Interrupted Status because InterruptedException clears the
// interrupted flag
Thread.currentThread.interrupt();
// Now stop doing your task and terminate
return;
}
doLongRunningStuff();
}
当你有任何抛出InterruptedException的方法时,一定要停止你正在做的事情并在抛出一个时终止。
以这种方式实现方法后,可以调用future.cancel(true)来取消正在运行的任务的执行。
答案 1 :(得分:5)
您的程序永远不会终止,因为您创建了一个ScheduledExecutorService
,它拥有一个线程池,但您永远不会关闭该服务。因此,线程池中的用户线程永远不会终止,因此VM会一直运行。
要解决此问题,您需要在执行程序服务上调用shutdown()
。这甚至可以在安排您要执行的任务后直接完成:
public static void main(String[] args) {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture scheduledFuture = executorService.schedule(new Callable() {
public Void call() {
doSomething();
return null;
}
}, 1, TimeUnit.SECONDS);
executorService.shutdown();
}
这将正常执行计划任务,然后终止池中的线程。
答案 2 :(得分:1)
您需要致电scheduledExecutorService.shutdown()
以停止执行。否则它会每秒重新启动。
(编辑:见评论)