[英]How do I use CompletableFuture.supplyAsync together with PriorityBlockingQueue?
我正在尝试通过CompletableFuture.supplyAsync将优先级队列添加到使用ThreadPoolExecutor和LinkedBlockingQueue的现有应用程序。 问题是我无法想出一个设计来分配任务优先级,然后我可以在PriorityBlockingQueue的Comparator中访问。 这是因为我的任务被CompletableFuture包装到一个名为AsyncSupply的私有内部类的实例中,该实例隐藏了私有字段中的原始任务。 然后使用这些AsteSupply对象作为Runnables调用Comparator,如下所示:
public class PriorityComparator<T extends Runnable> implements Comparator<T> {
@Override
public int compare(T o1, T o2) {
// T is an AsyncSupply object.
// BUT I WANT SOMETHING I CAN ASSIGN PRIORITIES TOO!
return 0;
}
}
我调查了扩展CompletableFuture的可能性,因此我可以将它包装在一个不同的对象中,但很多CompletableFuture被封装且不可用。 因此,扩展它似乎不是一种选择。 也没有用适配器封装它,因为它实现了非常宽的接口。
除了复制整个CompletableFuture并修改它之外,我不确定如何解决这个问题。 有任何想法吗?
似乎是API中的限制, CompletableFuture
不提供使用PriorityBlockingQueue
的简单方法。 幸运的是,我们可以毫不费力地破解它。 在Oracle的1.8 JVM中,它们恰好命名了所有内部类的字段fn
,因此可以毫不费力地提取我们的优先级感知的Runnable
:
public class CFRunnableComparator implements Comparator<Runnable> {
@Override
@SuppressWarnings("unchecked")
public int compare(Runnable r1, Runnable r2) {
// T might be AsyncSupply, UniApply, etc., but we want to
// compare our original Runnables.
return ((Comparable) unwrap(r1)).compareTo(unwrap(r2));
}
private Object unwrap(Runnable r) {
try {
Field field = r.getClass().getDeclaredField("fn");
field.setAccessible(true);
// NB: For performance-intensive contexts, you may want to
// cache these in a ConcurrentHashMap<Class<?>, Field>.
return field.get(r);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new IllegalArgumentException("Couldn't unwrap " + r, e);
}
}
}
这假定您的Supplier
类别是Comparable
,例如:
public interface WithPriority extends Comparable<WithPriority> {
int priority();
@Override
default int compareTo(WithPriority o) {
// Reverse comparison so higher priority comes first.
return Integer.compare(o.priority(), priority());
}
}
public class PrioritySupplier<T> implements Supplier<T>, WithPriority {
private final int priority;
private final Supplier<T> supplier;
public PrioritySupplier(int priority, Supplier<T> supplier) {
this.priority = priority;
this.supplier = supplier;
}
@Override
public T get() {
return supplier.get();
}
@Override
public int priority() {
return priority;
}
}
使用如下:
PriorityBlockingQueue<Runnable> q = new PriorityBlockingQueue<>(11 /*default*/,
new CFRunnableComparator());
ThreadPoolExecutor pool = new ThreadPoolExecutor(..., q);
CompletableFuture.supplyAsync(new PrioritySupplier<>(n, () -> {
...
}), pool);
如果您创建了诸如PriorityFunction
和PriorityBiConsumer
类的类,则可以使用相同的技术来调用thenApplyAsync
和whenCompleteAsync
等方法以及适当的优先级。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.