2016-08-19 10 views
1

ExecutorService에 제출 된 Callable 개체를 사용하여 S3에서 파일을 다운로드하는 프로그램이 있습니다. 파일 크기가 크고 다운로드하는 데 몇 분이 걸립니다. 다운로더에서 미래를 가져 와서 완성을 지켜 보는 또 다른 Callable 클래스를 만드는 것이 합리적입니까? 나의 최종 목표는 모든 전체 다운로드를 캐시 내의 중앙에 위치한 List에 추가하는 것입니다. 예를 들어Watching Future <T> ExecutorService를 사용하여 완료 할 개체

대신 자원을 소비는 '감시자'를 만드는

public void add(final String s3urlToDownload){ 

    Future<S3Object> futureS3obj = cachedPoolExecutor.submit(new S3Downloader(s3urlToDownload)); 

    // Instead of calling futureS3obj.get() and waiting, submit the Future to the "Watcher" service. 
    // Within FutureWatcher, the S3Object will be added to the List once the download is complete. 
    cachedPoolExecutor.submit(new FutureWatcher(downloadedList, futureS3obj)) 

} 
+0

이미 '미래'가있는 경우 추가로 '호출 가능'이란 이점은 무엇입니까? – Kayaman

+0

@Kayaman, 제 생각에'Future'의'get()'메소드를 호출하면'add' 메소드가 차단 될 것입니다. 그것이 내가 새로운 Callable'FutureWatcher'를 제출 한 이유입니다. – dmux

+0

그래서'Callable'은 어떤 역할을합니까? 그것의'call()'메소드를 호출하는 것은'get()'에 위임하기 때문에 역시 차단 될 것이다. – Kayaman

답변

1

여기 가짜 개체가 있습니다. "다운로드"무작위 잠 있습니다 : 우리는 파일을 다운로드하는 작업을 정의 할 수 있습니다

// for illustration only 
class S3Object { 
    String id; 
} 

// for illustration only 
class S3Downloader { 

    public S3Object download(String url) { 
     int min = 2; 
     int max = 5; 
     Random rand = new Random(); 
     int random = rand.nextInt((max - min) + 1) + min; 

     try { Thread.sleep(1000 * random); } catch (Exception ex) {} 
     S3Object result = new S3Object(); 
     result.id = url; 
     return result; 
    } 
} 

이하는 (thread에 대해서 안전한)리스트를 업데이트하고, CountDownLatch 감소 :

class MyTask implements Runnable { 
    private final List<S3Object> list; 
    private final CountDownLatch latch; 
    private final String url; 

    public MyTask(List<S3Object> list, CountDownLatch latch, String url) { 
     this.list = list; 
     this.latch = latch; 
     this.url = url; 
    }  

    public void run() { 
     S3Downloader downloader = new S3Downloader(); 
     S3Object result = downloader.download(url); 
     list.add(result); 
     latch.countDown(); 
    } 
} 

예 러너가 보여 "클라이언트". go 방법은 드라이버, 그리고 (차단하지 않는)을 add 방법을 사용 가능하게 오류를 처리해야

public class Runner { 
    private ExecutorService pool = Executors.newCachedThreadPool(); 
    private int numUrls = 20; 
    private CountDownLatch latch = new CountDownLatch(numUrls); 
    private List<S3Object> results = Collections.synchronizedList(new ArrayList<S3Object>()); 

    public void add(String url) { 
     pool.submit(new MyTask(results, latch, url)); 
    } 

    public void go() throws Exception { 

     for(int i = 0; i < numUrls; i++) { 
      String url = "http://example" + i; 
      add(url); 
     } 

     // wait for all downloads 
     latch.await(); 

     for (S3Object result : results) { 
      System.out.println("result id: " + result.id); 
     } 
    } 
} 

생산 코드가 적절한 클라이언트를 재구성.

+0

Michael 감사합니다. 위의 프레임 워크를 포함하도록 코드를 리팩터링 할 수 있어야합니다. – dmux

0

는 현재 다운로드가 완료에 마스터에게 통지합니다.