Executor 将提交 Runnable 与决定其运行位置分离。
ExecutorService 增加生命周期管理和 submit;Callable<V> 可以返回值或抛出受检查异常,
而 Future<V> 表示最终结果。Future.get() 建立任务完成前执行的操作所需的可见性。
Future<Result> future = pool.submit(() -> compute(input));
try {
return future.get();
} catch (ExecutionException e) {
throw new ServiceException(e.getCause());
}使用 synchronized、Lock、原子类、并发集合或消息传递来建立 happens-before 关系。
执行器提供调度能力,并不会自动保证可变共享对象的安全。
AQS 和同步器 #
AbstractQueuedSynchronizer(AQS)是锁、信号量、闩锁及相关同步器的框架。
子类维护一个原子整数状态,并实现获取/释放尝试。发生竞争时,AQS 将等待线程加入类似 FIFO
的同步队列,并使用 LockSupport 挂起线程;释放时唤醒符合条件的后继线程。
条件变量使用关联的条件队列,并在收到信号时将等待者移回同步队列。
队列顺序本身并不是普遍的公平性保证。
ThreadPoolExecutor 接纳任务 #
ThreadPoolExecutor 首先创建工作线程,直到达到 corePoolSize;然后将任务排队;
只有队列拒绝任务时才会向 maximumPoolSize 增长;达到上限后则拒绝任务。
因此,无界 LinkedBlockingQueue 实际上会阻止线程数超过核心线程数,
而 SynchronousQueue 会积极创建工作线程,直到达到最大值。
核心数量以上的空闲工作线程会在 keepAliveTime 后终止;显式启用时,核心线程也可以超时。
应根据工作负载证据、内存限制和下游系统容量选择有界队列并确定其大小。
工作线程工厂控制名称、守护线程状态和未捕获异常处理。
AbortPolicy 抛出异常,CallerRunsPolicy 通过让提交者执行任务施加背压,
DiscardPolicy 丢弃工作,DiscardOldestPolicy 在重试前移除排队最久的工作。
只有调用方能够容忍时,才可以静默丢弃任务。
生命周期、取消和可见性 #
cancel(true) 将 Future 标记为已取消,并在任务运行时请求中断;
中断是协作式的,因此阻塞操作必须传播或恢复中断状态,CPU 密集型任务必须轮询该状态。
取消不会回滚副作用。
shutdown() 拒绝新任务,但允许排队任务完成。shutdownNow() 尝试中断工作线程,
并返回尚未开始的任务。在应用边界调用 awaitTermination。
当前 JDK 中,Executors 工厂方法提供固定线程、单线程、定时、工作窃取和虚拟线程执行器,
但显式构造 ThreadPoolExecutor 能让队列和拒绝策略便于审查。
当 ExecutorService 的生命周期属于词法作用域时,始终关闭它。
评论
在 GitHub 上阅读或评论(发表评论需要登录)