SingleThreadEventExecutor

644 阅读5分钟

1 类的继承关系

image.png

2 代码详情

SingleThreadEventExecutor

类签名

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor

是一个抽象类

继承自AbstractScheduledEventExecutor

实现了OrderedEventExecutor接口,OrderedEventExecutor接口没有任何的方法,它是是一个标记性质的接口,表示的一个串行的EventExecutor

顾名思义它是单线程的

字段

private final Queue taskQueue;任务队列

private volatile Thread thread;线程

private volatile ThreadProperties threadProperties;线程属性

private final Executor executor;jdk中的接口

private volatile boolean interrupted;

private final CountDownLatch threadLock = new CountDownLatch(1);

private final Set shutdownHooks = new LinkedHashSet();

private final boolean addTaskWakesUp;

private final int maxPendingTasks;

private final RejectedExecutionHandler rejectedExecutionHandler;

private long lastExecutionTime;

private volatile int state = ST_NOT_STARTED;

  • SingleThreadEventExecutor总共有一下这几种状态
  • 还没有启动private static final int ST_NOT_STARTED = 1;
    
  • 已经启动: private static final int ST_STARTED = 2;
  • 正在关闭: private static final int ST_SHUTTING_DOWN = 3;
  • 已经关闭: private static final int ST_SHUTDOWN = 4;
  • 已终止: private static final int ST_TERMINATED = 5;

private volatile long gracefulShutdownQuietPeriod;

private volatile long gracefulShutdownTimeout;

private long gracefulShutdownStartTime;

private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);

构造函数:protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,boolean addTaskWakesUp, int maxPendingTasks,RejectedExecutionHandler rejectedHandler)

参数

  • EventExecutorGroup parent:用于给父类AbstractEventExecutor#parent赋值

  • Executor executor,会对这个Executor进行装饰使得在提交给executor执行的Runnable中,调用ThreadExecutorMap.currentExecutor返回的是this 这个eventExecutor

    • this.executor = ThreadExecutorMap.apply(executor, this);
  • boolean addTaskWakesUp给this.addTaskWakesUp赋值,为true,则addTask(Runnable)会唤醒执行器线程

  • int maxPendingTasks,给this.maxPendingTasks赋值,但是最小值16,表示任务被拒绝前最多可以挂起多少任务

  • RejectedExecutionHandler rejectedHandler,拒绝策略

new一个长度为this.maxPendingTasks的LinkedBlockingQueue然后给 this.taskQueue赋值

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,boolean addTaskWakesUp, Queue taskQueue,RejectedExecutionHandler rejectedHandler)

参数

  • EventExecutorGroup parent:用于给父类AbstractEventExecutor#parent赋值

  • Executor executor,会对这个Executor进行装饰使得在提交给executor执行的Runnable中,调用ThreadExecutorMap.currentExecutor返回的是this 这个eventExecutor

    • this.executor = ThreadExecutorMap.apply(executor, this);
  • boolean addTaskWakesUp给this.addTaskWakesUp赋值,为true,则addTask(Runnable)会唤醒执行器线程

  • taskQueue给this.taskQueue赋值

  • RejectedExecutionHandler rejectedHandler,拒绝策略

this.maxPendingTasks=Integer的最大值或者依赖于系统变量

public boolean inEventLoop(Thread thread)

return thread == this.thread;

判断这个线程是否在eventLoop中,如果它和SingleThreadEventExecutor中的this.thread是一个对象则是在eventLoop中

public void execute(Runnable task)

SingleThreadEventExecutor对jdk中的这个接口的实现

调用私有方法 private void execute(Runnable task, boolean immediate),其中执行!(task instanceof LazyRunnable) && wakesUpForTask(task)去判断是否需要立即执行immediate

目前wakesUpForTask是直接return true

private void execute(Runnable task, boolean immediate)

判断当前线程是否在eventloop中

  • boolean inEventLoop = inEventLoop();
    

加入到任务队列this.taskQueue中:addTask(task);

如果当前线程在eventloop中则,如果addTaskWakesUp为false,且immediate=true则调用 wakeup(inEventLoop);唤醒

不在eventloop中则

  • 启动线程: startThread();
  • 如果SingleThreadEventExecutor已经关闭:isShutdown()则执行一下操作:
  • 在任务队列中删除该任务:removeTask(task)
  • 删除成功则执行reject();该方法会抛jdk中的异常:RejectedExecutionException

protected void addTask(Runnable task)

执行offerTask(task),如果return false则执行reject(task);

final boolean offerTask(Runnable task)

如果已经关闭:isShutdown()=true,则执行reject();否则调用taskQueue.offer(task);

protected static void reject()

throw new RejectedExecutionException("event executor terminated");

public boolean isShutdown()

return state >= ST_SHUTDOWN;

state >= 关闭

private void startThread()

1 将this.state的状态由ST_NOT_STARTED通过cas变成ST_STARTED

2 真正启动线程doStartThread();

3 如果启动线程失败则,通过cas在把this.state 由ST_STARTED改成ST_NOT_STARTED

private void doStartThread()

核心代码

断言this.thread == null,这个变量是用于存储执行eventloop的线程的

向this.executor提交一个Runnable,于是executor中的一个线程会执行这个Runnable

  • 获取当前的线程给this.thread赋值,于是this.thread就存储了执行eventloop的线程了

  • 如果this.interrupted = true, 则打断线程thread.interrupt();

  • 更新最后一次执行任务的时间戳this.lastExecutionTime

  • 调用SingleThreadEventExecutor.this.run();去执行#taskQueue中的任务,这个方法在SingleThreadEventExecutor中抽象方法

  • finally中执行

    • 进入一个无限循环中,直到this.state被通过cas改成了ST_SHUTTING_DOWN

    • 无限调用confirmShutdown(),直到这个方法返回true

    • 进入一个无限循环中,直到this.state被通过cas改成了ST_SHUTDOWN

    • 再一次调用 confirmShutdown();

    • 在finally中执行

      • cleanup();这个方法是抽象方法

      • finally语句中执行

        •              FastThreadLocal.removeAll(); https://github.com/netty/netty/issues/6596.
          
        • 将this.state改成ST_TERMINATED
        • private final CountDownLatch threadLock = new CountDownLatch(1);对这个变量执行: threadLock.countDown();
          
        • 抽干任务队列drainTasks();,如果还有任务的话,则需要打日志
        • 对变量 private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);调用 terminationFuture.setSuccess(null);

protected boolean confirmShutdown()

确定是否可以关闭

1 判断是否正在关闭isShuttingDown():state >= ST_SHUTTING_DOWN;

2 必须在eventloop中否则抛出异常:throw new IllegalStateException("must be invoked from an event loop");

3 取消所有的定时任务,并清空优先级队列: AbstractScheduledEventExecutor#cancelScheduledTasks();

4 记录下this.gracefulShutdownStartTime

5 跑所有的任务,包括SingleThreadEventExecutor#Queue taskQueue;和父类中的优先级队列中的定时任务

  • 1 将父类AbstractScheduledEventExecutor中优先级队列中的ScheduledFutureTask删掉,然后投入SingleThreadEventExecutor#Queue taskQueue;中
  • 2 遍历taskQueue所有的Runnable,依次执行
  • 3 调用钩子方法 afterRunningAllTasks();它在SingleThreadEventExecutor中是空实现的

6 如果5中没有任务了,那么则跑所有的shutdown 钩子: private final Set shutdownHooks,跑完之后,清空shutdownHooks

7 有任务跑,或者有钩子跑的话 ,那么就返回

  • 如果已经关闭,则return true
  • 如果gracefulShutdownQuietPeriod=0, 则返回true
  • 否则:taskQueue.offer(WAKEUP_TASK); return false;

8 当前没有任务了,钩子也跑过了则

  • 如果已经关闭,则return true

  • 当前时间-关闭起始时间this.gracefulShutdownStartTime > 关闭超时时长gracefulShutdownTimeout,则return true

  • if (nanoTime - lastExecutionTime <= gracefulShutdownQuietPeriod)

    • taskQueue.offer(WAKEUP_TASK);
    • Thread.sleep(100);
    • return false;
  • 否则:return true

public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit)

语义:要等过了quietPeriod这么多时间都没有任务提交的话,才会关闭,但是如果过了timeout,就会强行关闭

1 检验

  •  quietPeriod必须大于等于0:ObjectUtil.checkPositiveOrZero(quietPeriod, "quietPeriod");
    
  • if (timeout < quietPeriod) ,则抛异常
  • ObjectUtil.checkNotNull(unit, "unit");

3 如果状态是>=ST_SHUTTING_DOWN,返回terminationFuture

4 进入一下无限循环里面执行一下代码

  • 如果状态是>=ST_SHUTTING_DOWN,返回terminationFuture

  • 计算新的状态

    • 如果当前线程在eventloop中则新状态是ST_SHUTTING_DOWN
    • 如果当前线程不在eventloop中,则如果当前状态是ST_NOT_STARTED后者ST_STARTED的话,则新状态是ST_SHUTTING_DOWN,否则新状态等于老状态
  • 用cas将this.state改成新状态,cas成功则跳出循环

5 确保线程启动:ensureThreadStarted(oldState),如果启动失败则返回terminationFuture

6 如果线程启动成功,如果在eventloop中,或者不在eventloop中,但是此时已经进入关闭流程了,则执行

  • taskQueue.offer(WAKEUP_TASK);
  • if (!addTaskWakesUp) { wakeup(inEventLoop); }

7 return terminationFuture

public boolean awaitTermination(long timeout, TimeUnit unit)

1 检验

  • ObjectUtil.checkNotNull(unit, "unit");
  • if (inEventLoop()) { throw new IllegalStateException("cannot await termination of the current thread"); }

2 threadLock.await(timeout, unit);

  • private final CountDownLatch threadLock = new CountDownLatch(1);

3 return isTerminated();