Java:创建大量Callables或将迭代器结果分配给线程?

时间:2013-06-03 12:09:51

标签: java parallel-processing

我写了一个操作图像的应用程序。我的操作代码应该应用于文件夹中的所有图像(每个文件夹最多1百万个)。

到目前为止,对于文件夹中的每个图像,我创建了一个Callable(操作图像的工作者)并将其添加到ArrayList。然后,我使用invokeAll的{​​{1}}方法来并行化工作。

然而,我的问题是:这是一个好的设计吗?我有点怀疑首先在阵列列表中添加100万个元素真的很有意义。我正在考虑将FixedThreadPool(通过文件)传递给所有线程并让每个线程获取下一个元素并处理它(不幸的是当然遇到阻塞问题) - 但这有意义吗?

2 个答案:

答案 0 :(得分:3)

即使它不一定非常有效并且不能很好地扩展,我听起来还不错。另一种设计可能是:

  • 创建一个比你的FixedThreadPool更大的ArrayBlockingQueue<File>(说两倍大)
  • 创建一个FileVisitor,让我们称之为ImageFileVisitor,这是visitFile方法puts队列中访问过的文件 - 这是一个阻塞调用,所以它会等待直到队列未满
  • 创建与池大小一样多的Callable,并从队列中创建每个take并执行他们必须执行的操作

注意:线程池的大小应该相当小。如果您的图像处理非常繁重,请使用处理器的数量,如果它有点微不足道,并且大部分时间花在读/写文件上,请使用较小的尺寸。

答案 1 :(得分:1)

FixedThreadPool使用LinkedBlockingQueue的{​​{1}}:

Integer.MAX_VALUE

所以,它的情感非阻塞,就像你可以public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } / offer百万put个实例一样,这肯定是对数百万的内存的不经意使用尽管你的Runnable会比5/10小得多。

直接改进此方案的一种方法是使用具有有限队列大小的fixedPoolSize

FixedThreadPool

通过上述计划,您的int nThreads = 10; int maxQSize = 1000; ExecutorService service = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(maxQSize)) 来电将在put 1000 Q {{}}} {}}} {}}} {{}} {}}} {{}}通过执行put,将有10个正在运行的线程和最多1000个可运行的实例。