我正在尝试理解其API中提供的java.util.concurrent.Executor
接口的以下示例实现。
class SerialExecutor implements Executor {
final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
final Executor executor;
Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}
在这里,传递的可运行实例被包装到另一个可运行实例中并存储在任务队列中,然后调用scheduleNext()
。传递的可运行实例是否(防御性地)复制到其他可运行实例?如果没有,除了执行队列中的下一个 Runnables,这样做有什么用?
请澄清我的疑问。
您希望仅在第一个任务完成后scheduleNext()
第二个任务。
将原始 Runnable 包装到另一个调用它并在调用 scheduleNext()
之后调用 是一种方便可靠的方法。
这样,您只需一个线程即可"生产使用"和"队列管理"。
另一种方法是单独的后台线程,用于监视当前正在运行的任务(例如通过join()
),然后计划一个新任务。
传递的可运行实例是否(防御性地)复制到其他可运行实例?
没有。当然,指向 Runnable 的指针被复制,但它仍然指向同一个 Runnable。它不是"防御性的",因为理论上可以在排队时更新 Runnable 的状态。
如果没有,除了执行队列中的下一个 Runnables,这样做有什么用?
为什么这还不够理由?毕竟,它必须完成。