这似乎是API中的一个限制,CompletableFuture
没有提供直接使用PriorityBlockingQueue
的方法。幸运的是,我们可以在没有太多麻烦的情况下绕过它。在Oracle的1.8 JVM,他们碰巧命名所有的内部类字段fn
的,所以提取我们的首要任务感知Runnable
S可没有太多的麻烦来完成:
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
以及适当的优先级。
我不明白你的问题。你正在调用'asyncSupply()'并传递一个配置了'LinkedBlockingQueue'的Executor?你想用'PriorityBlockingQueue'取代它?也就是说,似乎所有这些都在'supplyAsync()'函数和'CompletableFuture'的外部。你在哪里遇到麻烦?也许你可以显示你想写的代码,中间缺少的位突出显示。 – erickson
谢谢@erickson回复,并提出一个很好的问题。我没有注意到为什么我不能只使用PriorityBlockingQueue的重要一点。所以原因是PriorityBlockingQueue会传递给比较器:compare方法将两个AsyncSupply对象转换为Runnables。这个AsyncSupply是CompletableFuture的一个私有的内部类,所以我不能将它转换回AsyncSupply,更不用说访问它的私有字段,该字段引用我想要分配优先级的原始未解包任务。所以我想这个问题是:我如何或在哪里分配我的优先事项?我会添加一些代码。 – jacob