【发布时间】:2015-08-07 08:54:01
【问题描述】:
我正在尝试加速使用ExecutorService 并行运行任务的程序。它基本上是这样工作的:
初始化大小为
n的固定大小线程池读取一堆(大约 2500 个文件)包含任务输入的 XML 文件
使用池中的工作线程处理 XML 文件
一切都按预期工作,但我遇到的问题是每个工作线程都有一个对输入数据进行计算的类的实例。此实例存储在ThreadLocal 中。现在,所有这些线程本地实例都是在启动相应的工作线程时创建的,这意味着在读取所有 XML 输入文件之后。
由于计算对象的初始化需要相当长的时间,我宁愿让线程池从一开始就初始化所有工作线程,以便计算对象的初始化可以与输入文件的读取并行运行。
这里有一些代码可以帮助您了解它当前的工作方式(我删除了与问题无关的代码)。
初始化线程池和线程本地:
private final ExecutorService executor = Executors.newFixedThreadPool(Math.max(1, Runtime
.getRuntime().availableProcessors() - 1));
private ThreadLocal<Calculator> calculator = new ThreadLocal<Calculator>() {
@Override
protected Calculator initialValue() {
try {
Calculator instance = createCalculator();
return instance;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
};
提交新的计算:
@Override
public FutureTask<Output> calc(Input input) {
FutureTask<Output> task = new FutureTask<>(
new Callable<Rueckgabe>() {
@Override
public Output call() throws Exception {
try {
return calculator.get().calc(input);
} catch (Throwable e) {
System.err.println("Exception: " + e.getMessage());
e.printStackTrace(System.err);
return null;
}
}
});
executor.execute(task);
return task;
}
让ExecutorService 从一开始就为池启动所有工作线程的正确方法是什么?还是我必须使用 n 虚拟任务来强制初始化?
PS:由于 IT 限制,我必须在可预见的未来使用 Java 7。
【问题讨论】:
-
似乎我在 JDK 源代码中找到了一些东西。我可以将
Executors.newFixedThreadPool的返回值转换为ThreadPoolExecutor并调用prestartAllCoreThreads:((ThreadPoolExecutor) executor).prestartAllCoreThreads()。但是没有一种干净的方法可以做到这一点(即不依赖newFixedThreadPool()实现并且需要强制转换)? -
ExecutorsAPI 只是为了简化常见用例的使用。当您需要更多控制权时,请自行实例化ThreadPoolExecutor。它与Executors一样是公共 API。
标签: java multithreading threadpool executorservice