对于我的Java项目,我想并行执行两个任务并结合他们的结果。问题是我必须在每次执行(可能是1000或更多)时多次调用的方法中执行此操作。 我尝试使用ExecutorService及其线程池,但如果我将ExecutorService声明为类字段并开始向其提交工作,则会在某个时刻抛出一个
java.lang.OutOfMemoryError: unable to create new native thread
所以我决定使用这段代码:
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Integer> taskOne = executor.submit(new Callable<Integer> () {
public Integer call() throws Exception {
//Do work...
return 0;
}
});
Future<Integer> task2 = executor.submit(new Callable<Integer> () {
public Integer call() throws Exception {
//Do work...
return 0;
}
});
task1.get();
task2.get();
executor.shutdown();
while(!executor.isTerminated());
问题是,使用这种新方法,与单线程解决方案相比,应用程序性能更差。我认为这是由于在每次方法调用上创建新线程池的开销。
所以,我的问题是:有没有办法完成同样的任务但是不必每次调用方法都创建和关闭线程池?
谢谢。
答案 0 :(得分:1)
我不一定会说它本身就是劣质设计,但需要考虑一些事情。就个人而言,我喜欢线程池,如果使用得当,它是一个强大的解决方案。
您的性能下降的原因是,如果固定池大小为2,则一次只能运行两个线程。有可能你需要一个更大的数字 - 可能是10,可能是100 - 但至少你可以设置它以便你不会耗尽内存。
也就是说,如果原始设计内存不足,因为创建的线程太多,你肯定需要一次限制活动线程的数量,所以你的性能会受到一些打击......它只是没有&# 39; t需要全部或全部。
你也可以使用一个无限的执行程序线程池,假设正在运行的线程确实及时返回,这样你仍然不会超出线程。如果线程以某种确定的方式返回,当一个线程返回到池时,它立即可用于下一个可用任务,而不必创建任何东西。所以这很好。
所有人都说,看看异常消息,在操作系统级别上,无论您在Java中做了什么,都无法创建更多线程。我有一个在CentOS上运行的服务,我合法地必须增加每个进程允许的线程数(在这种情况下,一个运行我的服务的Java进程),因为有一个最大值,我正在点击它。如果您正在运行一些Linux风格,那也可能就是这样,特别是因为看起来线程本身除了返回之外什么都不做。
答案 1 :(得分:0)
您描述的类字段解决方案听起来像是一个更好的设计。那个游泳池的大小是多少?您应该调试OutOfMemoryError
而不是切换到劣质设计。