- 所有超级接口:
AutoCloseable,EventLoopGroup,Executor,ExecutorService,FixedEventLoopGroup,IExecutor,IExecutorService,IScheduledExecutorService,Iterable<EventLoop>,ScheduledExecutorService,SingleThreadExecutor
- 所有已知实现类:
AbstractEventLoop,DisruptorEventLoop
事件循环
它是单线程的,它保证任务不会并发执行,且任务的执行顺序和提交顺序一致。
1.如果 task1 的执行时间小于等于 task2 的执行时间,且 task1 先提交成功,则保证 task1 在 task2 之前执行。
它可以表述为:不保证后提交的高优先级的任务能先执行。
还可以表述为:消费者按照提交成功顺序执行是合法的。
(简单说,提高优先级是不保证的,但反向的优化——降低优先级,则是可以支持的)
1. 如果两个
2. 如果在
3. 如果
时序
在EventLoopGroup的基础上,我们提供这样的时序保证:1.如果 task1 的执行时间小于等于 task2 的执行时间,且 task1 先提交成功,则保证 task1 在 task2 之前执行。
它可以表述为:不保证后提交的高优先级的任务能先执行。
还可以表述为:消费者按照提交成功顺序执行是合法的。
(简单说,提高优先级是不保证的,但反向的优化——降低优先级,则是可以支持的)
2.周期性任务的再提交 与 新任务的提交 之间不提供时序保证。
它可以表述为:任务只有首次运行时是满足上面的时序的。
如果你期望再次运行和新任务之间得到确定性时序,可以通过提交一个新任务代替自己实现。
(简单说,允许降低周期性任务的再执行优先级)
3. schedule系列方法的initialDelay和delay为负时,将转换为0。
fixedRate除外,fixedRate期望的是逻辑时间,总逻辑时间应当是可以根据次数计算的,转0会导致错误,因此禁止负数输入。
另外,fixedRate由于自身的特性,因此难以和非fixedRate类型的任务达成时序关系。
Q:为什么首次触发延迟小于0时可以转为0?
A:我们在上面提到,由于不保证后提交的任务能在先提交的任务之前执行,因此当多个任务都能运行时,按照提交顺序执行是合法的。
因此,我们只要保证能按照提交顺序执行就是合法的,当所有的初始延迟都负转0时,所有后续提交的任务的优先级都小于等于当前任务,
因此后续提交的任务必定在当前任务之后执行,也就是按照提交顺序执行,因此是合法的。
警告
由于EventLoop都是单线程的,你需要避免死锁等问题。1. 如果两个
EventLoop存在交互,且其中一个使用有界任务队列,则有可能导致死锁,或大量任务超时。2. 如果在
EventLoop上执行阻塞或死循环操作,则可能导致死锁,或大量任务超时。3. 如果
EventLoop支持自定义等待策略,要小心选择或实现,可能导致定时任务不能被及时执行。- 作者:
- wjybxx date 2023/4/7
-
方法概要
修饰符和类型方法说明default voiddefault voidensureInEventLoop(String method) boolean测试当前线程是否是Executor所在线程。booleaninEventLoop(Thread thread) 测试给定线程是否是当前事件循环线程 1.注意:EventLoop接口约定是单线程的,不会并发执行提交的任务,但不约定整个生命周期都在同一个线程上,以允许在空闲的时候销毁线程。boolean是否处于运行状态事件循环的主模块 主模块是事件循环的外部策略实现,用于暴露特殊的业务接口 (Agent对内,MainModule对外,都是为了避免继承扩展带来的局限性)parent()返回该EventLoop线程所在的线程组(管理该EventLoop的容器)。IFuture<?> 等待线程进入运行状态的future future会在EventLoop成功启动的时候进入完成状态default EventLoopselect()选择一个EventLoop用于接下来的任务调度default EventLoopselect(int key) IFuture<?> start()主动启动EventLoop 一般而言,我们可以不主动启动EventLoop,在提交任务时会自动启动EventLoop,但如果我们需要确保EventLoop处于正确的状态才能对外提供服务时,则可以主动启动时EventLoop。state()voidwakeup()唤醒线程 如果当前EventLoop线程陷入了阻塞状态,则将线程从阻塞中唤醒;通常用于通知线程及时处理任务和响应关闭。从接口继承的方法 cn.wjybxx.concurrent.EventLoopGroup
awaitTermination, isShutdown, isShuttingDown, isTerminated, iterator, shutdown, shutdownNow, terminationFuture从接口继承的方法 java.util.concurrent.ExecutorService
close从接口继承的方法 cn.wjybxx.concurrent.FixedEventLoopGroup
childCount从接口继承的方法 cn.wjybxx.concurrent.IExecutorService
invokeAll, invokeAll, invokeAny, invokeAny, newPromise, submit, submit, submit, submit, submitAction, submitAction, submitAction, submitAction, submitFunc, submitFunc, submitFunc, submitFunc从接口继承的方法 cn.wjybxx.concurrent.IScheduledExecutorService
newScheduledPromise, schedule, schedule, schedule, scheduleAction, scheduleAtFixedRate, scheduleFunc, scheduleWithFixedDelay从接口继承的方法 java.lang.Iterable
forEach, spliterator
-
方法详细资料
-
select
从接口复制的说明:EventLoopGroup选择一个EventLoop用于接下来的任务调度- 指定者:
select在接口中EventLoopGroup- 返回:
- this - 由于
EventLoop表示单个线程,因此总是分配自己。
-
select
从接口复制的说明:FixedEventLoopGroup通过一个键选择一个EventLoop这提供了第二种绑定线程的方式,第一种方式是通过EventLoopGroup.select()分配一个线程,让业务对象持有EventLoop的引用。 现在,你可以为用户分配一个键,通过键建立虚拟绑定。- 指定者:
select在接口中FixedEventLoopGroup- 参数:
key- 计算索引的键;限定int可保证选择性能- 返回:
- this - 由于
EventLoop表示单个线程,因此总是选中自己
-
parent
返回该EventLoop线程所在的线程组(管理该EventLoop的容器)。 如果没有父节点,返回null。 -
inEventLoop
boolean inEventLoop()测试当前线程是否是Executor所在线程。 主要作用: 1.判断是否可访问线程封闭的数据。 2.防止死锁。警告:如果用户基于该测试实现分支逻辑,则可能导致时序错误,eg:
假设现在有3个线程:A、B、C,它们进行了约定,线程A投递任务后,告诉线程B,线程B投递后告诉线程C,线程C再投递,以期望任务按照A、B、C的顺序处理。 在某个巧合下,线程C可能就是执行者线程,结果C的任务可能在A和B的任务之前被处理,从而破坏了外部约定的时序。if(eventLoop.inEventLoop()) { doSomething(); } else{ eventLoop.execute(() -> doSomething()); }该方法一定要慎用,它有时候是无害的,有时候则是有害的,因此必须想明白是否需要提供全局时序保证!
- 指定者:
inEventLoop在接口中SingleThreadExecutor
-
inEventLoop
测试给定线程是否是当前事件循环线程 1.注意:EventLoop接口约定是单线程的,不会并发执行提交的任务,但不约定整个生命周期都在同一个线程上,以允许在空闲的时候销毁线程。 如果当前线程死亡,EventLoop是可以开启新的线程的,因此外部如果捕获了当前线程的引用,该引用可能失效。 (有一个经典的示例:Netty的GlobalEventExecutor) 2.该方法可用于任务检测是否切换了线程,以确保任务运行在固定的线程中- 指定者:
inEventLoop在接口中SingleThreadExecutor
-
wakeup
void wakeup()唤醒线程 如果当前EventLoop线程陷入了阻塞状态,则将线程从阻塞中唤醒;通常用于通知线程及时处理任务和响应关闭。 如果线程已停止,则该方法不产生影响 -
mainModule
EventLoopModule mainModule()事件循环的主模块 主模块是事件循环的外部策略实现,用于暴露特殊的业务接口 (Agent对内,MainModule对外,都是为了避免继承扩展带来的局限性) -
ensureInEventLoop
default void ensureInEventLoop()- 抛出:
GuardedOperationException- 如果当前不在EventLoop所在线程
-
ensureInEventLoop
- 抛出:
GuardedOperationException- 如果当前不在EventLoop所在线程
-
state
EventLoopState state()- 返回:
- EventLoop的当前状态
-
isRunning
boolean isRunning()是否处于运行状态 -
runningFuture
IFuture<?> runningFuture()等待线程进入运行状态的future future会在EventLoop成功启动的时候进入完成状态1.如果EventLoop启动失败,则Future进入失败完成状态 2.如果EventLoop未启动直接关闭,则Future进入失败完成状态 3.EventLoop关闭时,Future保持之前的结果
-
start
IFuture<?> start()主动启动EventLoop 一般而言,我们可以不主动启动EventLoop,在提交任务时会自动启动EventLoop,但如果我们需要确保EventLoop处于正确的状态才能对外提供服务时,则可以主动启动时EventLoop。 另外,通过提交任务启动EventLoop,是无法根据任务的执行结果来判断启动是否成功的。- 返回:
runningFuture()
-