2015-12-02 58 views
1

这是继续通过earlier post,作为我的任务的一部分,我试图从URL下载文件使用可调用,并且每当发生异常我试图重新提交相同的可调用再次最大次数。终止和提交可执行文件到执行器

问题是,用目前的方法,我的程序并没有在一个快乐的一天的场景中完成所有的可调参数后终止,它会一直运行(可能是因为我使用的是非守护线程?不是吗?在给定的时间之后终止?)。

此外,我相信目前的设计将会阻止再次提交失败的可调用对象,因为我打电话给executor.shutdown(),因此无论何时可调用失败,执行程序都将阻止向执行队列添加新的可调用对象。

任何想法如何克服?

public class DownloadManager { 

int allocatedMemory; 
private final int MAX_FAILURES = 5; 
private ExecutorService executor; 
private CompletionService<Status> completionService; 
private HashMap<String, Integer> failuresPerDownload; 
private HashMap<Future<Status>, DownloadWorker> URLDownloadFuturevsDownloadWorker; 

public DownloadManager() { 
    allocatedMemory = 0; 
    executor = Executors.newWorkStealingPool(); 
    completionService = new ExecutorCompletionService<Status>(executor); 
    URLDownloadFuturevsDownloadWorker = new HashMap<Future<Status>, DownloadWorker>(); 
    failuresPerDownload = new HashMap<String, Integer>(); 
} 

public ArrayList<Status> downloadURLs(String[] urls, int memorySize) throws Exception { 
    validateURLs(urls); 
    for (String url : urls) { 
     failuresPerDownload.put(url, 0); 
    } 
    ArrayList<Status> allDownloadsStatus = new ArrayList<Status>(); 
    allocatedMemory = memorySize/urls.length; 
    for (String url : urls) { 
     DownloadWorker URLDownloader = new DownloadWorker(url, allocatedMemory); 
     Future<Status> downloadStatusFuture = completionService.submit(URLDownloader); 
     URLDownloadFuturevsDownloadWorker.put(downloadStatusFuture, URLDownloader); 
    } 
    executor.shutdown(); 
    Future<Status> downloadQueueHead = null; 
    while (!executor.isTerminated()) { 
     downloadQueueHead = completionService.take(); 
     try { 
      Status downloadStatus = downloadQueueHead.get(); 
      if (downloadStatus.downloadSucceeded()) { 
       allDownloadsStatus.add(downloadStatus); 
       System.out.println(downloadStatus); 
      } else { 
       handleDownloadFailure(allDownloadsStatus, downloadStatus.getUrl()); 

      } 
     } catch (Exception e) { 
      String URL = URLDownloadFuturevsDownloadWorker.get(downloadQueueHead).getAssignedURL(); 
      handleDownloadFailure(allDownloadsStatus, URL); 
     } 
    } 
    return allDownloadsStatus; 
} 

private void handleDownloadFailure(ArrayList<Status> allDownloadsStatus, String URL) { 
    int failuresPerURL = failuresPerDownload.get(URL); 
    failuresPerURL++; 
    if (failuresPerURL < MAX_FAILURES) { 
     failuresPerDownload.put(URL, failuresPerURL); 
     // resubmit the same job 
     DownloadWorker downloadJob = URLDownloadFuturevsDownloadWorker.get(URL); 
     completionService.submit(downloadJob); 
    } else { 
     Status failedDownloadStatus = new Status(URL, false); 
     allDownloadsStatus.add(failedDownloadStatus); 
     System.out.println(failedDownloadStatus); 
    } 
    }     
} 

更新:之后我已经改变了while循环的条件,而非计数器!executor.isTerminated()它的工作。 为什么执行者不会终止?

回答

0

您需要致电ExecutorService.shutdown()awaitTermination()以在所有工作完成后终止线程。

或者,在构建ExecutorService时,您可以提供自己的ThreadFactory,并将所有线程标记为守护进程,以便在主线程退出后它们不会让进程保持活动状态。

+0

我调用shutdown()提交可调用之后但它并没有终止 –

0

ExecutorCompletionService的javadoc,我们看到的例子

CompletionService<Result> ecs 
     = new ExecutorCompletionService<Result>(e); 
    List<Future<Result>> futures 
     = new ArrayList<Future<Result>>(n); 
try { 
... 
} finally { 
     for (Future<Result> f : futures) 
      f.cancel(true); 
    } 

所以尝试调用取消(真)与所有的未来,当你需要停止ExecutorCompletionService