对于我的用例,我需要一个可以根据优先级执行任务的执行程序。实现此目的的简单方法是使用具有PriorityBlockingQueue的线程池并覆盖newTaskFor()以返回基于任务优先级可比较的自定义未来任务。
//Define priorities
public enum Priority {
HIGH, MEDIUM, LOW, VERYLOW;
}
优先任务
//A Callable tasks that has priority. Concrete implementation will implement
//call() to do actual work and getPriority() to return priority
public abstract class PriorityTask<V> implements Callable<V> {
public abstract Priority getPriority ();
}
实际执行者实施
public class PriorityTaskThreadPoolExecutor <V> {
int _poolSize;
private PriorityBlockingQueue<Runnable> _poolQueue =
new PriorityBlockingQueue<Runnable>(500);
private ThreadPoolExecutor _pool;
public PriorityTaskThreadPoolExecutor (int poolSize) {
_poolSize = poolSize;
_pool = new ThreadPoolExecutor(_poolSize, _poolSize, 5, TimeUnit.MINUTES,
_poolQueue) {
//Override newTaskFor() to return wrap PriorityTask
//with a PriorityFutureTaskWrapper.
@Override
protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
return new PriorityFutureTaskWrapper<V>((PriorityTask<V>) c);
}
};
_pool.allowCoreThreadTimeOut(true);
}
public Future<V> submit (PriorityTask<V> task) {
return _pool.submit(task);
}
}
//A future task that wraps around the priority task to be used in the queue
class PriorityFutureTaskWrapper<V> extends FutureTask<V>
implements Comparable <PriorityFutureTaskWrapper<V>> {
PriorityTask<V> _priorityTask;
public PriorityFutureTaskWrapper (PriorityTask<V> priorityTask) {
super(priorityTask);
_priorityTask = priorityTask;
}
public PriorityTask<V> getPriorityTask () {
return _priorityTask;
}
@Override
public int compareTo(PriorityFutureTaskWrapper<V> o) {
return _priorityTask.getPriority().ordinal() -
o.getPriorityTask().getPriority().ordinal();
}
}
问题在于,在我的用例中,低优先级任务可能会永远饿死。我想避免这种情况。我找不到使用java中可用的执行程序/池执行此操作的简洁方法。所以我想写自己的执行者。我有两种不同的方法。
1)具有PriorityBlockingQueue的自定义线程池。将有一个单独的线程,检查队列中的任务年龄。旧的任务将被删除,并以升级的优先级重新添加。
2)我的用例只有少数优先级,例如1-4。每个优先级我将有4个不同的队列。现在,自定义池中的线程(而不是阻塞队列)将在必须接收下一个任务时按以下顺序扫描队列。
40%线程 - Q1,Q2,Q3,Q4
30%线程 - Q2,Q1,Q3,Q4
20%线程 - Q3,Q1,Q2,Q4
10%线程 - Q4,Q1,Q2,Q3
当线程通知队列中的新添加或该线程执行的当前任务完成时,将由线程完成扫描。其他时候,线程将等待。但是,与阻塞队列相比,扫描效率会更低一些。
Apprach 2更适合我的用例。
是否有人尝试过这些方法或类似用例的不同方法?有什么想法/建议?