我在Java 1.6中使用ExecutoreService,简单地开始
ExecutorService pool = Executors.newFixedThreadPool(THREADS).
当我的主线程完成时(以及线程池处理的所有任务),此池将阻止我的程序关闭,直到我显式调用
pool.shutdown();
我可以避免不得不通过某种方式将此池使用的内部线程管理变为deamon线程来调用它吗?或者我在这里遗漏了一些东西。
可能最简单和首选的解决方案是在Marco13's answer,所以不要被投票差异所欺骗(我的回答是几年之久)或接受标记(它只是意味着我的解决方案适合OP情况而不是最好)。
您可以使用ThreadFactory
将Executor中的线程设置为守护进程。这将影响执行程序服务,它也将成为守护程序线程,因此如果没有其他非守护程序线程,它(以及由它处理的线程)将停止。这是一个简单的例子:
ExecutorService exec = Executors.newFixedThreadPool(4,
new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = Executors.defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
}
});
exec.execute(YourTaskNowWillBeDaemon);
但是如果你想获得执行器,它将完成它的任务,同时在应用程序完成时自动调用它的shutdown()
方法,你可能想用Guava's MoreExecutors.getExitingExecutorService
包装你的执行器。
ExecutorService exec = MoreExecutors.getExitingExecutorService(
(ThreadPoolExecutor) Executors.newFixedThreadPool(4),
100_000, TimeUnit.DAYS//period after which executor will be automatically closed
//I assume that 100_000 days is enough to simulate infinity
);
//exec.execute(YourTask);
exec.execute(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("daemon");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
});
已经有一个内置的功能来创建一个ExecutorService
,在一段时间不活动后终止所有线程:你可以创建一个ThreadPoolExecutor
,传递所需的时间信息,然后在这个执行器服务上调用allowCoreThreadTimeout(true)
:
/**
* Creates an executor service with a fixed pool size, that will time
* out after a certain period of inactivity.
*
* @param poolSize The core- and maximum pool size
* @param keepAliveTime The keep alive time
* @param timeUnit The time unit
* @return The executor service
*/
public static ExecutorService createFixedTimeoutExecutorService(
int poolSize, long keepAliveTime, TimeUnit timeUnit)
{
ThreadPoolExecutor e =
new ThreadPoolExecutor(poolSize, poolSize,
keepAliveTime, timeUnit, new LinkedBlockingQueue<Runnable>());
e.allowCoreThreadTimeOut(true);
return e;
}
编辑参考注释中的注释:请注意,当应用程序退出时,此线程池执行程序不会自动关闭。执行程序将在应用程序退出后继续运行,但不会超过
keepAliveTime
。如果,根据精确的应用程序要求,keepAliveTime
必须长于几秒钟,answer by Pshemo中的解决方案可能更合适:当线程设置为守护程序线程时,它们将在应用程序退出时立即结束。
我会使用Guava的ThreadFactoryBuilder类。
ExecutorService threadPool = Executors.newFixedThreadPool(THREADS, new ThreadFactoryBuilder().setDaemon(true).build());
如果你还没有使用Guava,我会选择一个类似于Pshemo's answer顶部描述的ThreadFactory子类
是。
您只需要创建自己的ThreadFactory
类来创建守护程序线程而不是常规线程。
如果您只想在一个地方使用它,那么您可以在线使用qazxsw poi实现,例如对于具有4个线程的池,您将编写(示例显示为假定Java 1.8或更新版本的lambda):
java.util.concurrent.ThreadFactory
但我通常希望我的所有Thread工厂都生成守护程序线程,所以我添加了一个实用程序类,如下所示:
ExecutorService pool = Executors.newFixedThreadPool(4,
(Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
);
这让我可以轻松地将import java.util.concurrent.ThreadFactory;
public class DaemonThreadFactory implements ThreadFactory {
public final static ThreadFactory instance =
new DaemonThreadFactory();
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
传递到DaemonThreadFactory.instance
,例如
ExecutorService
或者用它来轻松地从ExecutorService pool = Executors.newFixedThreadPool(
4, DaemonThreadFactory.instance
);
启动一个守护程序线程,例如:
Runnable
这个解决方案与@ Marco13类似,但我们可以修改DaemonThreadFactory.instance.newThread(
() -> { doSomething(); }
).start();
返回的解决方案,而不是创建我们自己的ThreadPoolExecutor
。这是如何做:
Executors#newFixedThreadPool(int nThreads)
你可以使用Guava的ThreadFactoryBuilder。我不想添加依赖项,我想要Executors.DefaultThreadFactory的功能,所以我使用了组合:
ExecutorService ex = Executors.newFixedThreadPool(nThreads);
if(ex instanceof ThreadPoolExecutor){
ThreadPoolExecutor tp = (ThreadPoolExecutor) ex;
tp.setKeepAliveTime(time, timeUnit);
tp.allowCoreThreadTimeOut(true);
}
如果您有已知的任务列表,则根本不需要守护程序线程。您可以在提交所有任务后在ExecutorService上调用shutdown()。
当主线程完成时,使用awaitTermination()方法为已提交任务的完成留出时间。当前提交的任务将被执行,线程池将在完成后终止其控制线程。
class DaemonThreadFactory implements ThreadFactory {
final ThreadFactory delegate;
DaemonThreadFactory() {
this(Executors.defaultThreadFactory());
}
DaemonThreadFactory(ThreadFactory delegate) {
this.delegate = delegate;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = delegate.newThread(r);
thread.setDaemon(true);
return thread;
}
}