我试图找到一种方法,如何在具有一定最大线程限制的多个线程中加载多个网页,以便在完成时加载新页面。页面下载后还应该有另一个后处理线程来处理加载的内容,以便整个过程被链接起来。
我想如何做到:
任务队列保存应下载的页面
线程池有一定数量的线程下载任务队列中的页面(加载页面需要一些时间,因此线程数 线程数可以远高于CPU核心数)
当页面下载完成时,线程应通知此情况,以便可以启动队列中的新任务
当页面下载完成后,内容应转移到另一个任务队列进行后处理
另一个线程池的线程数与 CPU 的核心数相同(猜测每个核心只有一个线程用于后处理是最快的),该线程池对下载的页面执行后处理。
当一个页面的后处理完成时,线程应该通知它,以便队列中的另一个页面可以被后处理
当所有页面都已下载完毕(队列为空)时,可以关闭第一个线程池,当两个任务队列都为空时(所有页面都已下载并进行后处理),可以关闭另一个线程池
我有类似的东西:
for (int j = 0; j < threads.length; j++) {
threads[j].start();
}
for (int j = 0; j < threads.length; j++) {
threads[j].join();
}
但是这样所有要加载的页面都同时在单独的线程中,我想限制线程的数量。更重要的是,我想重用线程,并在一项任务完成后让线程执行下一项任务。我可以用 while 循环来做到这一点,但这就是我想要避免的,我不想用 while 循环来检查队列是否有更多任务以及线程是否空闲。是否可以使用某种回调,以便线程告诉池已完成并返回数据。 我还希望下载任务将内容存储在数据结构中并将其进一步添加到后处理任务队列中。
到目前为止我发现的最好的资源是: Thread pools Callback
但我不知道是否可以按照我想要的方式创建它。我一直在思考函数指针。
最佳答案
不要使用低级线程方法来执行此操作。有一个 downloadExecutor 线程池,并将 DownloadTask
实例(实现 Runnable
或 Callable
)提交到该池。
在 DownloadTask 代码的末尾,将 PostProcessPageTask 实例(再次实现 Runnable
或 Callable
)提交给第二个 postProcessExecutor
线程池。
您可以使用一两个 CountDownLatch 实例,每个任务完成后都会递减,并让主线程等待此(或这些)锁存器以了解何时必须关闭线程池。
参见http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html和 docs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html 了解更多信息。
关于Java 任务队列、线程池和带有回调的线程,用于通知新任务何时可以启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9430376/