Executor的设计定位是什么? 怎么玩?
今天摸自己的小项目时,从来不写并发的我突然想加入一点异步功能,翻开spring 官方教程,发现用到了ThreadPoolTaskExecutor,封装了juc里面的ThreadPoolExecutor,简单使用倒是也没啥问题吧,但是本着钻研精神还是要把整套东西翻出来看看的😿
Executor在j.u.c中的设计定位
-
在我看来,想了解一个类,最好不要直接莽源码,而是先看看它所在的包,看看它的周边长啥样,然后观察它的设计定位,最后再去读源码,这样有助于理解和对体系产生比较整体直观的认识
-
所以这里我想说的Executor并不只是指那个接口Executor,而是指代Executor的一个继承体系,就像TCP/IP指代整个TCP/IP协议族一样
-
所以j.u.c中有哪几套体系?根据API文档,j.u.c大致分为以下几块
-
Executors:线程池,异步IO,轻量级的任务框架
-
Queues:
LinkedBlockingQueue
,ArrayBlockingQueue
,SynchronousQueue
,PriorityBlockingQueue
, andDelayQueue
维护线程池的阻塞队列
-
Timing: TimeUnit枚举类,提供各种时间单位,用于各种超时判断等
-
Synchronizers:几个核心类,比较倾向操作系统调度原理的实现
Semaphore
经典的基于信号量机制的并发类CountDownLatch
基于信号量机制,配合Semaphore使用- A
CyclicBarrier
is a resettable multiway synchronization point useful in some styles of parallel programming.并行计算用 - A
Phaser
provides a more flexible form of barrier that may be used to control phased computation among multiple threads. - An
Exchanger
allows two threads to exchange objects at a rendezvous point, and is useful in several pipeline designs 多管道通信相关
-
Concurrent Collections:并发集合类,不用多说了吧,核心中的核心,非常重要
-
Memory Consistency Properties:保证可见性和同步(happens-before)
-
-
再结合Executor系列的API可以发现,Executor系列的主要任务就是将并发任务解耦为以下三部分
- 线程创建,线程管理,线程复用 ThreadPool
- 任务执行 Executor.submit()/execute()
- 接收结果集 Future
相互独立,分工明确,从而形成解耦,可以说是非常的Object Orient啊☕️
Executor内部分层
-
Task层:指定提交的任务,具体来讲就是实现了Callable & Runnable接口的对象
-
ExecutorSerivice层:生产各种用途不同的线程池,可以通过静态工厂Executors.newXXXXThreaPool(n)拿到(也可以自己定义ThreadPoolExecutor),然后执行提交的任务
- FixedThreadPool,固定大小的线程池
- CacheThreadPool,可扩展能自动回收的线程池
- ScheduleThreadPool,支持周期任务
- WorkStealingPool
- SingleThreadExecutor,只运行单个线程的线程池
- SingleThreadScheduledExecutor,支持周期任务的单线程池
- 以及自定义的ThreadPoolExecutor
-
Future层:接受Executor执行的结果
举个简单的例子就是:创建执行器服务(ExecutorService)->指定线程池大小->提交任务->返回结果
ExecutorService service=Executors.newFixedThreadPool(10);
String example = service.submit(() -> { //Callable是Functional Interface,可以直接走Lambda表达式
System.out.println("This is a example");
return "Task Over";
}).get();
和直接走Thread又有什么区别呢?
功能上看,似乎没什么大不了的,但是Executor框架做到了以下几件事:
- 自动管理线程,最大程度地减小线程创建和销毁所造成的额外开销
- 减少线程切换上下文产生的开销