使用ExecutorService的Java应用程序从不关闭
我正在尝试编写一个程序,将工作分配给几个java工作线程。问题是,当我从命令行运行它时,它永远不会返回。我没有得到提示,最终必须按ctrl-c键关闭程序 我已经把它简化为下面的一个小例子使用ExecutorService的Java应用程序从不关闭,java,multithreading,executorservice,completable-future,Java,Multithreading,Executorservice,Completable Future,我正在尝试编写一个程序,将工作分配给几个java工作线程。问题是,当我从命令行运行它时,它永远不会返回。我没有得到提示,最终必须按ctrl-c键关闭程序 我已经把它简化为下面的一个小例子 import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestExeServ {
private class ExpensiveTask implements Callable<Integer>{
private final String msg;
public ExpensiveTask(String str){
this.msg = str;
}
@Override
public Integer call() {
System.out.println( "My message was " + msg);
return 1;
}
}
private void run()
{
final ExecutorService exeServ = Executors.newFixedThreadPool(2);
Future<Integer> result = exeServ.submit(new ExpensiveTask("Hello!") );
try {
System.out.println( " Task is done, it returned " + result.get());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[])
{
System.out.println( "Start");
TestExeServ tes = new TestExeServ();
tes.run();
System.out.println( "Done");
}
}
就这样。它挂在那里。没有提示。如果我删除ExecutorService.submit行,我将获得
djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ
Start
done
djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$
节目自然结束
是否有一些清理任务需要在ExecutorService上执行,但我没有正确执行?我假设.get()调用加入了线程。不是这样吗?您必须调用或终止执行器的线程池。否则线程将保持活动状态,从而防止JVM终止
从类Javadoc:
ExecutorService可能会被关闭,这将导致它拒绝新任务。为关闭Executor服务提供了两种不同的方法。shutdown()
方法允许在终止之前执行以前提交的任务,而shutdownNow()
方法防止等待的任务启动并尝试停止当前正在执行的任务。终止后,执行者没有正在执行的任务,没有等待执行的任务,也不能提交新任务
请注意,作为最后一种手段,您正在使用的ThreadPoolExecutor
将在垃圾收集时自动关闭-其finalize()
方法调用shutdown()
。但是,最好不要依赖于此并明确关闭执行器
正如@mre在评论中所说的,我将明确说明-您可以安全地在
run()
方法的末尾调用exeServ.shutdown()
,因为Future.get()
将被阻止,所以当代码执行在get()
之后时,您不需要;我不再需要遗嘱执行人了。但是,如果这是更复杂的实际场景的简化版本,则可能需要找到正确的位置来安全地调用shutdown()
您必须调用或终止执行器的线程池。否则线程将保持活动状态,从而防止JVM终止
从类Javadoc:
ExecutorService可能会被关闭,这将导致它拒绝新任务。为关闭Executor服务提供了两种不同的方法。shutdown()
方法允许在终止之前执行以前提交的任务,而shutdownNow()
方法防止等待的任务启动并尝试停止当前正在执行的任务。终止后,执行者没有正在执行的任务,没有等待执行的任务,也不能提交新任务
请注意,作为最后一种手段,您正在使用的ThreadPoolExecutor
将在垃圾收集时自动关闭-其finalize()
方法调用shutdown()
。但是,最好不要依赖于此并明确关闭执行器
正如@mre在评论中所说的,我将明确说明-您可以安全地在
run()
方法的末尾调用exeServ.shutdown()
,因为Future.get()
将被阻止,所以当代码执行在get()
之后时,您不需要;我不再需要遗嘱执行人了。但是,如果这是更复杂的实际场景的简化版本,则可能需要找到正确的位置来安全地调用shutdown()
您需要关闭Executor或使用生成守护程序线程的线程工厂。或者设置标记allowCoreThreadTimeout您需要关闭Executor或使用生成守护程序线程的线程工厂。或者设置标记allowCoreThreadTimeout和ShutdowNow
是可以的,因为结果。get
将阻塞,直到任务完成完成,否则您将面临取消任务的风险。shutdownow
可以,因为result.get
将一直阻止,直到任务完成,否则您将面临取消任务的风险。
djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ
Start
done
djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$