2012-08-27 1 views
1

다음 예제 코드가 있는데 다른 하나가 1 초보다 빨리 실행될 때 MyCallable("B")이 1 초보다 오래 걸린다 고 가정 해 봅시다. 따라서 Future.get()을 호출하는 루프 내에서 TimeoutException이 발생합니다. MyCallable 각각의 예상대로ExecutorService 및 Futures를 사용하여 TimeoutException을 처리하는 방법은 무엇입니까?

public static void main(String[] args) { 
    ExecutorService es = Executors.newFixedThreadPool(2); 

    List<Future<String>> futures = new ArrayList<Future<String>>(); 

    futures.add(es.submit(new MyCallable("A"))); 
    futures.add(es.submit(new MyCallable("B"))); 
    futures.add(es.submit(new MyCallable("C"))); 
    futures.add(es.submit(new MyCallable("D"))); 
    futures.add(es.submit(new MyCallable("E"))); 

    try { 
     for(Future<String> f : futures) { 
      try { 
       System.out.println("result " + f.get(1, TimeUnit.SECONDS)); 
      } 
      catch (TimeoutException e) { 
       // how do I know which MyCallable() has timed out? 
      } catch (ExecutionException e) { 
       System.out.println(e.getMessage()); 
      } 
     } 
    } 
    catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
    finally { 
     es.shutdown(); 
    } 
} 

() 인스턴스를 실행할 수 있지만, 시간이 초과 내가 몇 가지 오류 처리를 수행하고자하는 하나이는 Callable이있는 Future와 연관된 아는이 필요합니다.

이 연관을위한 메커니즘이 있습니까? call() 메서드 내에서 모든 오류 처리를 처리하려면 내 Callable까지입니까?

답변

0

List<Future<String>> 대신 Map<Future<String>, Callable<String>>을 유지하고 원래의 Callable을 이와 같이 검색하는 것처럼 보입니다.

정말 영리 해 지길 원한다면 OO 스타일로 ThreadPoolExecutor를 확장하고 Future 데코레이터 클래스를 만들 수 있습니다. 나는 이것이 아마 잔인한 생각하지만, 당신은 이런 식으로 할 수 있었다 : 다음

import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.TimeoutException; 


public class FutureWithCallable<T> implements Future<T> { 
    private final Callable<T> callable; 
    private final Future<T> wrapped; 

    public FutureWithCallable(Future<T> wrapped, Callable<T> callable) { 
     this.callable = callable; 
     this.wrapped = wrapped; 
    } 

    public Callable<T> getCallable() { 
     return callable; 
    } 

    @Override 
    public boolean cancel(boolean mayInterruptIfRunning) { 
     return wrapped.cancel(mayInterruptIfRunning); 
    } 

    @Override 
    public T get() throws InterruptedException, ExecutionException { 
     return wrapped.get(); 
    } 

    @Override 
    public T get(long timeout, TimeUnit unit) throws InterruptedException, 
      ExecutionException, TimeoutException { 
     return wrapped.get(timeout, unit); 
    } 

    @Override 
    public boolean isCancelled() { 
     return wrapped.isCancelled(); 
    } 

    @Override 
    public boolean isDone() { 
     return wrapped.isDone(); 
    } 
} 

과 :

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.Callable; 
import java.util.concurrent.Future; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 

    public class ExecutorServiceWithCallable extends ThreadPoolExecutor { 

     public ExecutorServiceWithCallable(int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { 
      super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue); 
     } 

     @Override 
     public <T> FutureWithCallable submit(Callable<T> callable) { 
      Future<T> future = super.submit(callable); 
      return new FutureWithCallable<T>(future, callable); 
     } 

    } 
+0

'Map , Callable > '을 사용하는 것이 가장 간단한 옵션이며 작동합니다 – Brad

0

공용 클래스 TimeoutException 은 예외에게 블록 조작이 타임 아웃했을 때에 발생 예외를 확장합니다. 시간 초과가 지정된 차단 조작에는 시간 초과가 발생했음을 나타내는 수단이 필요합니다. 이러한 많은 조작에서는, 타임 아웃을 나타내는 값을 돌려 줄 수가 있습니다. 그것이 불가능하거나 바람직하지 않은 경우 TimeoutException을 선언하고 throw해야합니다.

관련 문제