工作者完成后将新任务提交给执行者

时间:2018-06-30 08:55:24

标签: java multithreading concurrency future executor

我正在研究一个访问页面并提取链接以查找特定域的Web爬网程序,如果找不到,它将查看提取的链接并重复直到达到页面限制或找到页面为止。我发现自己正在努力提出合理的逻辑,以使该僵尸程序在提取链接后继续让任务排队,因为该任务正在快速完成,并且没有足够的时间来提交新提取的链接。我该如何实施,使搜寻器在没有执行程序的情况下等待其关闭,然后再关闭执行器?我已经包括了我的多线程实现的基本概述。我将最大线程数设置为3,并提交example.com 10次(种子域)

Spawn Thread访问站点并提取链接,然后将其返回为字符串。我的问题是我需要能够获得这些结果,然后将其放入队列。但是到那时队列已经完成。有什么建议么?

  

更新为了澄清,我的问题是,当我提交种子并获得结果时,我无法获取它来继续搜索返回的种子。   除非我阻止并等待结果,然后手动将其添加。

     

更新2 为了进一步说明,我试图防止在future.get上发生阻塞,因此我可以将返回的结果添加为它们   排定为任务。

            int MaxThreads = 3;
            ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(MaxThreads); // How many threads
            List<Future<String>> resultList = new ArrayList<>();// Create results list

            for (int i = 0; i < 10; i ++) {
                SpawnThread task  = new SpawnThread("example.com");// Create Tasks
                Future<String> result = executor.submit(task);//Launch tasks
                //System.out.println("Added " + CurrentNum + " to the que!");
                resultList.add(result);//Store Task Result
            }

             for(Future<String> future : resultList) //Loop through results
                {
                    String resultfinished;
                    try {
                        resultfinished = future.get();
                        System.out.println(resultfinished);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
            executor.shutdown();
  

我认为我需要的是一个非阻塞队列,其结果可以   重新添加到提供新域进行爬网的列表中,但是   我似乎无法使其正常工作。

BlockingQueue queue = new ArrayBlockingQueue(1024);
        Executor executor = Executors.newFixedThreadPool(4);
        CompletionService<List<String>> completionService = 
                 new ExecutorCompletionService<List<String>>(executor);
        List<String> pagesToVisit = new ArrayList<String>();
        Set<String> pagesVisited = new HashSet<String>();

        String SeedPage = "https://example.com/";
        String currentURL = null;

        boolean done = false;
        while(!done) {

             int listsize = pagesToVisit.size();
             if(pagesToVisit.isEmpty())
             {
                 currentURL = SeedPage;
                 pagesVisited.add(SeedPage);
                 listsize = pagesToVisit.size() + 1;
              }
             else
             {
                 currentURL = nextUrl();
             }


             for(int k = 0; k < listsize; k ++)
             {

                 completionService.submit(new Spider(currentURL,"IP","PORT" ) {
                 });
             }

              int received = 0;
              boolean errors = false;
              while(received < listsize  && !errors)
              {
                  Thread.sleep(1000);
                  Future<List<String>> resultFuture = completionService.take(); //blocks if none available
                  try
                  {
                      List<String> result = resultFuture.get();
                      pagesToVisit.addAll(result);
                      received ++; 
                  }
                  catch(Exception e)
                  {
                               //log
                            e.printStackTrace();
                            errors = true;
                  }
              }

          }

1 个答案:

答案 0 :(得分:0)

我不确定我是否让你问对了,但是

您可以使用awaitTermination();方法

  

布尔布尔awaitTermination(长时间超时,                          TimeUnit单位)                            抛出InterruptedException

     

阻塞,直到关闭后所有任务完成执行   请求,或者发生超时,或者当前线程被中断,   以先发生的为准。

     

参数:timeout-等待的最大时间单位-的时间单位   超时参数

     

返回值:如果该执行程序终止,则返回true;如果超时,则返回false   终止前已过去

     

抛出:InterruptedException-如果在等待时被中断

例如

try{
executor.awaitTermination(5, TimeUnit.Seconds);
}catch(InterruptedException e)
{
// Catch block
}

shutdown()方法不等待线程完成

  

启动有序关闭,在该关闭中执行先前提交的任务,但不接受任何新任务。如果已关闭,则调用不会产生任何其他影响。   此方法不等待先前提交的任务完成执行。