0

我正在使用 Java 中的线程编写应用程序,并且在循环中保持恒定数量的线程时遇到问题(新线程与新数据一起传入)。我使用 ExecutorService 来限制线程的数量,但是我在启动新线程时遇到了问题。

我有类似的东西:

ExecutorService execDownload = Executors.newFixedThreadPool(5);
UniqList<String> documentList = new UniqList<String>("startfile.txt");
        Future<UniqList<String>> future;
        while( !execDownload.isShutdown()) {
            future = execDownload.submit(new Parser(documentList.get(i)));
            i++;
            try {
                documentList.addAll(future.get());
            } catch (InterruptedException | ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

Parser 是一个可调用对象,它返回 UniqList。我将此列表中的元素添加到我的全局列表中,该列表是所有文档名称的集合。问题是:我希望同时运行恒定数量的解析器。如果我在程序启动之前知道所有文件的名称,那将很简单,因为如果我有 100 个文件名,我只应该调用 ExecutorService submit() 方法,即 100 次,但我不知道所有文件的名称 - 名称通过调用以下代码进行解析:

new Parser(documentList.get(i))

并且名称在文件中。所以再问一次问题 - 当新数据到达时,如何保持恒定数量的线程?在上面的代码中,我只有一个 Future 对象,我认为这是我最大的问题 - 我应该创建 Futures 数组吗?但是然后如何检测来自 ExecutorService 的某个线程何时刚刚返回了一些新数据......

算法应该是(我认为):

  1. 使用初始参数启动程序(第一个文档名称)
  2. 项目清单
  3. 通过将 Parser 类提交给 ExecutorService 来启动 Parser 类,并从开始文件中提取所有文档名称
  4. 将 #2 中的文档名称添加到全局文档名称列表
  5. 创建另一个线程并使用全局文档名称列表中的名称解析文档。启动最大线程数(受 ExecutorService 限制)。解析每个下一个文件并从中提取新文件名
  6. 将 #3 中的名称添加到全局文档名称 List back to #4

如您所见,它就像递归。我觉得和解析网站一样的问题,1个起始节点,一级分类,二级文章等等。

链接或示例代码将非常有用。谢谢你。

4

2 回答 2

0

我建议放弃未来,构建解析器以了解执行者:

execDownload.submit(new Parser(execDownload, documentList.get(i)));

让 Parser 将此“execDownload”ExecutorService 存储为成员变量。

在 Parser.run() 结束时,当您获得新解析的文档名称列表时,您可以为它们创建新的解析器,并安排它们:

foreach (String newDoc: UniqList)
{
     execDownload.submit(new Parser(execDownload, newDoc));
}
于 2012-12-20T19:15:38.870 回答
0

您的代码几乎是连续的:future.get() 阻塞直到任务完成,因此只要前一个任务正在运行,您就无法提交新任务。您可以:

  • 在一个循环中提交 N 个任务并存储未来然后尝试调用 get on one if the future 并提交一个新任务
  • 但这将是重新发明轮子:CompletionService似乎完全可以满足您的需求。
于 2012-12-20T19:12:53.520 回答