我写了一个操作图像的应用程序。我的操作代码应该应用于文件夹中的所有图像(每个文件夹最多1百万个)。
到目前为止,对于文件夹中的每个图像,我创建了一个Callable
(操作图像的工作者)并将其添加到ArrayList
。然后,我使用invokeAll
的{{1}}方法来并行化工作。
然而,我的问题是:这是一个好的设计吗?我有点怀疑首先在阵列列表中添加100万个元素真的很有意义。我正在考虑将FixedThreadPool
(通过文件)传递给所有线程并让每个线程获取下一个元素并处理它(不幸的是当然遇到阻塞问题) - 但这有意义吗?
答案 0 :(得分:3)
即使它不一定非常有效并且不能很好地扩展,我听起来还不错。另一种设计可能是:
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个可运行的实例。