هل هناك طريقة سهلة لتحويل المستقبل > إلى المستقبل ؟

StackOverflow https://stackoverflow.com/questions/2165167

  •  24-09-2019
  •  | 
  •  

سؤال

لقد حصلت على بعض التعليمات البرمجية التي تقدم طلبًا إلى مؤشر ترابط آخر قد يقدم أو لا يقدم هذا الطلب إلى موضوع آخر. هذا يعطي نوع العودة Future<Future<T>>. هل هناك بعض الطرق غير المثيرة لتحويل هذا على الفور إلى Future<T> هذا ينتظر الانتهاء من السلسلة المستقبلية بأكملها؟

أنا بالفعل أستخدم مكتبة الجوافة للتعامل مع أشياء أخرى للتزامن ممتعة وكبديل لمجموعات Google وعملها بشكل جيد ولكن لا يبدو أنني أجد شيئًا لهذه الحالة.

هل كانت مفيدة؟

المحلول

الجوافة 13.0 يضيف Futures.dereference لفعل هذا. يتطلب أ ListenableFuture<ListenableFuture>, ، بدلا من سهل Future<Future>. (تعمل على سهل Future سيتطلب مكالمة متوسطة ، تتطلب كل منها سلسلة رسائل مخصصة لعمر المهمة (كما هو أكثر وضوحًا بالاسم الجديد للطريقة ، JdkFutureAdapters.listenInPoolThread).)

نصائح أخرى

تطبيق آخر محتمل يستخدم مكتبات الجوافة وهو أكثر بساطة.

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);
      }
    });
  }
}

أعتقد أن هذا هو أفضل ما يمكن القيام به لتنفيذ عقد المستقبل. لقد أخذت لعبة Ascting Consing As Actlever قدر الإمكان حتى أتأكد من أنها تلبي العقد. ليس بشكل خاص تنفيذ الحصول على مهلة.

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
        }
      }
    }
  }
}

يمكنك إنشاء فصل مثل:

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
        }
    }
    ...
}

سيتعين عليك التعامل مع الاستثناءات التي يمكن أن ترفعها () ولكن لا يمكن أن تكون الأساليب الأخرى.

كانت هذه أول طعن لي ، لكنني متأكد من أن هناك الكثير من الخطأ في ذلك. سأكون أكثر من سعيد لاستبداله بشيء مثل 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);
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top