您可以通过将 Future 与 ComputedMap 一起使用来安排后台计算的“一次”执行。Future 代表计算值的任务。Future 由 ComputedMap 创建,同时传递给ExecutorService进行后台执行。可以使用您自己的ThreadFactory实现来配置执行器,该实现创建低优先级线程,例如
class LowPriorityThreadFactory implements ThreadFactory
{
public Thread newThread(Runnable r) {
Tread t = new Thread(r);
t.setPriority(MIN_PRIORITY);
return t;
}
}
当需要该值时,您的高优先级线程然后从映射中获取未来,并调用 get() 方法来检索结果,并在必要时等待计算结果。为了避免优先级倒置,您向任务添加了一些额外的代码:
class HandlePriorityInversionTask extends FutureTask<ResultType>
{
Integer priority; // non null if set
Integer originalPriority;
Thread thread;
public ResultType get() {
if (!isDone())
setPriority(Thread.currentThread().getPriority());
return super.get();
}
public void run() {
synchronized (this) {
thread = Thread.currentThread();
originalPriority = thread.getPriority();
if (priority!=null) setPriority(priority);
}
super.run();
}
protected synchronized void done() {
if (originalPriority!=null) setPriority(originalPriority);
thread = null;
}
void synchronized setPriority(int priority) {
this.priority = Integer.valueOf(priority);
if (thread!=null)
thread.setPriority(priority);
}
}
get()
如果任务尚未完成,这将负责将任务的优先级提高到线程调用的优先级,并在任务正常或其他方式完成时将优先级返回到原始优先级。(为了简短起见,代码不会检查优先级是否确实更高,但这很容易添加。)
当高优先级任务调用 get() 时,future 可能还没有开始执行。您可能想通过为执行程序服务使用的线程数设置较大的上限来避免这种情况,但这可能不是一个好主意,因为每个线程都可能以高优先级运行,消耗尽可能多的 cpu操作系统将其关闭。池的大小可能与硬件线程的数量相同,例如将池大小设置为Runtime.availableProcessors()
. 如果任务还没有开始执行,而不是等待执行者安排它(这是一种优先级反转的形式,因为您的高优先级线程正在等待低优先级线程完成),那么您可以选择取消它当前执行程序并在仅运行高优先级线程的执行程序上重新提交。