2015-12-02 75 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