与JAVA Executor的区别
vertx框架提供了OrderedExecutor的实现,其能保证提交的任务按照严格的提交顺序执行,在idk Executor的线程池中,多线程情况下可能无法保证提交的任务顺序执行。
源码分析
下面看下vertx的OrderedExecutor实现,其源码并不长,如下:
private static final class OrderedExecutor implements Executor {
private final LinkedList<Runnable> tasks = new LinkedList<>();
private boolean running;
private final Executor parent;
private final Runnable runner;
public OrderedExecutor(Executor parent) {
this.parent = parent;
runner = () -> {
for (; ; ) {
final Runnable task;
synchronized (tasks) {
task = tasks.poll();
if (task == null) {
running = false;
return;
}
}
try {
task.run();
} catch (Throwable t) {
log.error("Caught unexpected Throwable", t);
}
}
};
}
public void execute(Runnable command) {
synchronized (tasks) {
tasks.add(command);
if (!running) {
running = true;
parent.execute(runner);
}
}
}
}
OrderedExecutor包含4个成员变量,tasks(LinkedList<Runnable>)是runnable队列,parent(Executor)是真正执行runnable的执行器,runner(Runnable)是顺序执行器要执行的任务,running为运行状态标志。
首先分析runner,其运行的任务是个循环任务,只有当tasks中没有要执行的任务了才退出。其逻辑很简单,就是循环从tasks中获取任务并执行。
再看execute方法,其逻辑也很简单,就是向tasks中添加runnable,如果runner没有执行,那么就将其提交给parent线程池运行起来。
因为runner是按顺序从tasks中取任务执行的,因此保证了该OrderedExecutor execute的任务是按顺序执行的。
再介绍下创建OrderedExecutor的工厂类OrderedExecutorFactory,其代码如下:
public class OrderedExecutorFactory {
static final Logger log = LoggerFactory.getLogger(OrderedExecutorFactory.class);
private final Executor parent;
public OrderedExecutorFactory(Executor parent) {
this.parent = parent;
}
public OrderedExecutor getExecutor() {
return new OrderedExecutor(parent);
}
}
其代码更简单,就是传入一个线程池执行器parent,每次创建OrderedExecutor要共享这个parent执行器。
下面分析下OrderedExecutor和Executor的关系,虽然OrderedExecutor实现了Executor,但它们并不是简单的平行对等关系,1个Executor可以对应多个OrderedExecutor。
1个Executor相当于1个线程池,但每个OrderedExecutor在运行状态会独占1个线程,因为在把runner提交给parent执行时,parent会选出1个空闲线程执行该runner,而该runner是个循环任务,会独占这个线程。
OrderedExecutor通过1个runner任务处理所有提交到该OrderedExecutor的runnable,当处理完tasks中所有任务后就把线程归还给parent(Executor),当下次有新的runnable提交进来时再把runner提交给parent(Executor),parent再取出1个空闲线程运行runner,这个runner又独占了这个线程。