2016-03-07 83 views
0

对于我的Java项目,我想并行执行两个任务并合并它们的结果。问题是我必须在每次执行时调用多次(可能是1000次或更多)的方法中执行此操作。 我试着用的ExecutorService和线程池,但如果我宣布的ExecutorService作为一类领域,开始提交的工作吧,在某个时刻,它抛出一个Java - 重用线程池

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()); 

问题是,与单线程解决方案相比,采用这种新方法后,应用程序性能更差。我认为这是由于在每个方法调用上创建一个新的线程池的开销。

所以,我的问题是:有没有办法做同样的任务,但不必创建和关闭线程池每个方法的调用?

谢谢。

+1

在每次调用时创建一个线程池没有意义。你能发布原始代码吗? – shmosel

+0

'task1.get()'是一个阻塞操作,所以你已经有了两个任务结果。没有必要关闭执行程序并重新创建它。每次执行应用程序只执行一次。 – Cosu

回答

1

我不一定会说它本身就是一种劣质设计,但需要考虑一些事情。就我个人而言,我喜欢线程池,如果使用正确,它是一个强大的解决方案。

性能降低的原因是固定池大小为2时,只能同时运行两个线程。有可能你需要一个更大的数字 - 可能是10,可能是100 - 但至少你可以设计它,这样你就不会耗尽内存。也就是说,如果原始设计因为创建的线程太多而耗尽内存,那么您肯定需要一次限制活动的线程数,因此您的性能将会受到一些打击......它只是不会不需要全部或没有。

您也可以使用无限执行程序线程池,假设正在运行的线程确实以及时返回的方式返回,以至于仍然不会最大化线程。如果线程以某种确定的方式返回,当线程返回到池时,它将立即可用于下一个可用的任务,而无需创建任何东西。所以这很好。

大家都说,看看异常消息,也可能在操作系统级别,无法创建更多的线程,无论您在Java中做了什么。我有一个在CentOS上运行的服务,我合法地必须增加每个进程允许的线程数(在这种情况下,一个Java进程运行我的服务),因为有一个最大值,我打它。如果你正在运行某种linux风格,那也可能是这样,尤其是因为看起来线程本身除了返回外什么都不做。

+0

谢谢。最终的解决方案是将ExecutorService声明为静态字段,因为在我的代码中,我创建了许多同一类的实例,并且每个实例都有不同的ExecutorService,消耗了不必要的操作系统线程 –

0

您所描述的class field解决方案听起来像是一种更好的设计。游泳池的大小是多少?您应该调试OutOfMemoryError而不是切换到低级设计。