如何使用 Java 5 中的 ExecutorService 实现任务优先级?

2022-08-31 23:43:57

我正在实现一个线程池机制,我想在其中执行不同优先级的任务。我希望有一个很好的机制,通过这种机制,我可以向服务提交一个高优先级的任务,并将其安排在其他任务之前。任务的优先级是任务本身的固有属性(无论我是否将该任务表示为a或a对我来说并不重要)。CallableRunnable

现在,从表面上看,我可以使用 a 作为 my 中的任务队列,但该队列包含对象,这些对象可能是也可能不是我提交给它的任务。此外,如果我提交了任务,目前还不清楚这将如何映射。PriorityBlockingQueueThreadPoolExecutorRunnableRunnableCallable

有没有办法做到这一点?我真的宁愿不为此而掷骰子,因为我更有可能以这种方式出错。

(顺便说一句;是的,我知道在这样的事情上,低优先级工作可能会挨饿。额外加分(?!)对于有合理公平保证的解决方案)


答案 1

我已经以合理的方式解决了这个问题,我将在下面描述它,以供将来参考我自己和任何遇到Java Concurrent库问题的人。

使用 a 作为坚持任务以便以后执行的手段,确实是朝着正确方向前进的举动。问题在于,必须一般地实例化以包含实例,并且不可能在接口上调用(或类似)。PriorityBlockingQueuePriorityBlockingQueueRunnablecompareToRunnable

解决问题。创建执行器时,必须为其指定一个 .应进一步为队列提供一个自定义比较器,以执行正确的就地排序:PriorityBlockingQueue

new PriorityBlockingQueue<Runnable>(size, new CustomTaskComparator());

现在,看一看:CustomTaskComparator

public class CustomTaskComparator implements Comparator<MyType> {

    @Override
    public int compare(MyType first, MyType second) {
         return comparison;
    }

}

到目前为止,一切看起来都很直接。这里有点粘。我们的下一个问题是处理执行器创建的未来任务。在执行器中,我们必须这样覆盖:newTaskFor

@Override
protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
    //Override the default FutureTask creation and retrofit it with
    //a custom task. This is done so that prioritization can be accomplished.
    return new CustomFutureTask(c);
}

我们尝试执行的任务在哪里。现在,让我们来看看:cCallableCustomFutureTask

public class CustomFutureTask extends FutureTask {

    private CustomTask task;

    public CustomFutureTask(Callable callable) {
        super(callable);
        this.task = (CustomTask) callable;
    }

    public CustomTask getTask() {
        return task;
    }

}

请注意该方法。我们稍后将使用它从我们创建的这个任务中获取原始任务。getTaskCustomFutureTask

最后,让我们修改我们尝试执行的原始任务:

public class CustomTask implements Callable<MyType>, Comparable<CustomTask> {

    private final MyType myType;

    public CustomTask(MyType myType) {
        this.myType = myType;
    }

    @Override
    public MyType call() {
        //Do some things, return something for FutureTask implementation of `call`.
        return myType;
    }

    @Override
    public int compareTo(MyType task2) {
        return new CustomTaskComparator().compare(this.myType, task2.myType);
    }

}

您可以看到,我们在任务中实现将 委托给实际的 .ComparableComparatorMyType

你有它,使用Java库为执行器自定义优先级!这需要一些弯曲,但它是我能够想到的最干净的。我希望这对某人有帮助!


答案 2

乍一看,您似乎可以为任务定义一个扩展或和的接口。然后用 a 包装为队列,并且只接受实现接口的任务。RunnableCallable<T>ComparableThreadPoolExecutorPriorityBlockingQueue

考虑到您的注释,看起来一个选项是 扩展 ,并重写这些方法。参考 以查看默认的外观;他们所做的就是将 or 包裹在一个和它中。我可能会通过编写一个包装类来实现和委托给匿名内部.把它们包装在有你优先考虑的东西里,这样你就可以得到它。ThreadPoolExecutorsubmit()AbstractExecutorServiceRunnableCallableFutureTaskexecute()ExecutorServiceThreadPoolExecutorComparator


推荐