2010-01-29 6 views
19

요청을 다른 스레드에 제출할 수도 있고하지 않을 수도있는 다른 스레드에 요청을 제출하는 코드가 있습니다. 반환 유형은 Future<Future<T>>입니다. 앞으로이 전체 체인의 완성을 기다리는 Future<T>으로 즉시 전환 할 수있는 비 치명적인 방법이 있습니까?Future <Future<T>>을 미래의 <T>으로 바꾸는 쉬운 방법이 있습니까?

다른 재미있는 동시성 작업을 처리하고 Google Collections 및 그 잘 작동하는 작업을 대체하기 위해 이미 Guava 라이브러리를 사용하고 있지만이 경우 뭔가를 찾지 못하는 것 같습니다.)

public class UnwrapFuture<T> implements Future<T> { 
    Future<Future<T>> wrappedFuture; 

    public UnwrapFuture(Future<Future<T>> wrappedFuture) { 
     this.wrappedFuture = wrappedFuture; 
    } 

    public boolean cancel(boolean mayInterruptIfRunning) { 
     try { 
      return wrappedFuture.get().cancel(mayInterruptIfRunning); 
     } catch (InterruptedException e) { 
      //todo: do something 
     } catch (ExecutionException e) { 
      //todo: do something 
     } 
    } 
    ... 
} 

당신은 (얻을 예외를 처리해야 올릴 수 있지만, 다른 방법은 없습니다 :

+4

가능한 경우 유용 할 것입니다. 컨텍스트를 조금 더 추가하십시오. 분명한 대답은 get()을 호출하는 것이지만, 아마도 당신이 원하는 것은 아닙니다. –

+0

완료. 미안해. – Nik

+0

Monad가 필요한 것 같아요. – user

답변

5

구아바 13.0은 이렇게하기 위해 Futures.dereference을 추가합니다. 보통 Future<Future>이 아닌 ListenableFuture<ListenableFuture>이 필요합니다. (Future으로 작동하면 makeListenable 호출이 필요합니다. 각 호출에는 작업 수명 동안 전용 스레드가 필요합니다 (메서드의 새 이름 인 JdkFutureAdapters.listenInPoolThread에 의해 명확 해짐)

0

당신은 같은 클래스를 만들 수 있습니다.

+1

내가 피하려고했던 것. 또한 거기에있는 취소 방법은 체인의 첫 번째 미래가 완료 될 때까지 취소를 대기하게 만듭니다. 그게 내가 찾고있는 게 아니야. – Nik

+2

"미래의 전체 체인이 완료 될 때까지 기다리는 Future 으로 바꾸시겠습니까?" ... 두 번째 장래를 취소 할 수 있다고 생각하지 않습니다. 그러나 첫 번째 미래가 그것을 돌려 줄 때까지는 그것을 얻을 수 없습니다. – Dave

+0

잘자요. 두 번째 미래는 첫 번째 미래에 의해 창조 된 반면, 나는 당신이 첫 번째 미래를 취소 한 국가에 자신을 넣을 수 있지만 두 번째 미래는 어쨌든 만들며 취소 할 수 없다고 확신합니다. 첫 번째 미래에'Futures.makeListenable'-ing을 사용하여 문제를 해결할 수 있고 그 답장에 체인화 된 미래를 즉시 취소하는 리스너를 추가 할 수있을 것입니다. 그러면 문제는이 경우에 대한 테스트가됩니다. – Nik

0

이것은 내 첫 찌르기 였지만 그걸로는 많은 잘못이 있다는 것을 확신합니다. Futures.compress(f)과 같은 것으로 바꾸는 것만으로도 행복 할 것입니다.

public class CompressedFuture<T> implements Future<T> { 
    private final Future<Future<T>> delegate; 

    public CompressedFuture(Future<Future<T>> delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public boolean cancel(boolean mayInterruptIfRunning) { 
     if (delegate.isDone()) { 
      return delegate.cancel(mayInterruptIfRunning); 
     } 
     try { 
      return delegate.get().cancel(mayInterruptIfRunning); 
     } catch (InterruptedException e) { 
      throw new RuntimeException("Error fetching a finished future", e); 
     } catch (ExecutionException e) { 
      throw new RuntimeException("Error fetching a finished future", e); 
     } 
    } 

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

    @Override 
    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 
     long endTime = System.currentTimeMillis() + unit.toMillis(timeout); 
     Future<T> next = delegate.get(timeout, unit); 
     return next.get(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); 
    } 

    @Override 
    public boolean isCancelled() { 
     if (!delegate.isDone()) { 
      return delegate.isCancelled(); 
     } 
     try { 
      return delegate.get().isCancelled(); 
     } catch (InterruptedException e) { 
      throw new RuntimeException("Error fetching a finished future", e); 
     } catch (ExecutionException e) { 
      throw new RuntimeException("Error fetching a finished future", e); 
     } 
    } 

    @Override 
    public boolean isDone() { 
     if (!delegate.isDone()) { 
      return false; 
     } 
     try { 
      return delegate.get().isDone(); 
     } catch (InterruptedException e) { 
      throw new RuntimeException("Error fetching a finished future", e); 
     } catch (ExecutionException e) { 
      throw new RuntimeException("Error fetching a finished future", e); 
     } 
    } 
} 
1

나는 이것이 미래의 계약을 이행하기 위해 할 수 있다고 생각합니다. 나는 그것이 계약을 준수하는지 확신 할 수 있도록 가능한 한 험악한 태도를 취했다. 특히 타임 아웃을 사용하여 get을 구현하는 것은 아닙니다.

import java.util.concurrent.*; 

public class Futures { 
    public <T> Future<T> flatten(Future<Future<T>> future) { 
    return new FlattenedFuture<T>(future); 
    } 

    private static class FlattenedFuture<T> implements Future<T> { 
    private final Future<Future<T>> future; 

    public FlattenedFuture(Future<Future<T>> future) { 
     this.future = future; 
    } 

    public boolean cancel(boolean mayInterruptIfRunning) { 
     if (!future.isDone()) { 
     return future.cancel(mayInterruptIfRunning); 
     } else { 
     while (true) { 
      try { 
      return future.get().cancel(mayInterruptIfRunning); 
      } catch (CancellationException ce) { 
      return true; 
      } catch (ExecutionException ee) { 
      return false; 
      } catch (InterruptedException ie) { 
      // pass 
      } 
     } 
     } 
    } 

    public T get() throws InterruptedException, 
          CancellationException, 
          ExecutionException 
    { 
     return future.get().get(); 
    } 

    public T get(long timeout, TimeUnit unit) throws InterruptedException, 
                CancellationException, 
                ExecutionException, 
                TimeoutException 
    { 
     if (future.isDone()) { 
     return future.get().get(timeout, unit); 
     } else { 
     return future.get(timeout, unit).get(0, TimeUnit.SECONDS); 
     } 
    } 

    public boolean isCancelled() { 
     while (true) { 
     try { 
      return future.isCancelled() || future.get().isCancelled(); 
     } catch (CancellationException ce) { 
      return true; 
     } catch (ExecutionException ee) { 
      return false; 
     } catch (InterruptedException ie) { 
      // pass 
     } 
     } 
    } 

    public boolean isDone() { 
     return future.isDone() && innerIsDone(); 
    } 

    private boolean innerIsDone() { 
     while (true) { 
     try { 
      return future.get().isDone(); 
     } catch (CancellationException ce) { 
      return true; 
     } catch (ExecutionException ee) { 
      return true; 
     } catch (InterruptedException ie) { 
      // pass 
     } 
     } 
    } 
    } 
} 
7

구아바 라이브러리를 사용하는 다른 가능한 구현은 훨씬 간단합니다.

import java.util.concurrent.*; 
import com.google.common.util.concurrent.*; 
import com.google.common.base.*; 

public class FFutures { 
    public <T> Future<T> flatten(Future<Future<T>> future) { 
    return Futures.chain(Futures.makeListenable(future), new Function<Future<T>, ListenableFuture<T>>() { 
     public ListenableFuture<T> apply(Future<T> f) { 
     return Futures.makeListenable(f); 
     } 
    }); 
    } 
} 
+0

그게 그렇게 할거 같아. 내가 미래를 구아바에 위임하게 내버려 둬. – Nik

관련 문제