题记:
临近农历年关(对国人来说,这个才叫新年嘛),工作琐事较多,因此本月发博数量锐减至①篇。虽不以博文数量为目标,但每月一篇的数量还是说不过去。博文数量锐减,总结下来有两个原因:
第一,近期在花时间对比分析DICOM各大开源库中使用的各种线程池技术,诸如fo-dicom中的ThreadPoolQueue、ThreadPool,dcm4chee中的LF_ThreadPool、newCachedThreadPool、newSingleThreadScheduledExecutor等。但还未整理出思绪,未找到很好的切入点。
第二,原本计划中的每月“医疗时鲜资讯”系列,也因为资本市场的浮躁和自己的迷茫而找不新的吐槽点。
赶在农历新年放假前,整理出“DICOM开源库多线程分析系列”的第一篇博文。
背景:
之前博文DICOM:DICOM3.0网络通信协议之“开源库实现剖析”中,简短提到过fo-dicom开源库中使用的自定义线程池队列ThreadPoolQueue,以及dcm4chee中使用的java的Executors类中的newCachedThreadPool、 newSingleThreadScheduledExecutor。其中fo-dicom的ThreadPoolQueue是基于.NET系统ThreadPool线程池基础上添加了分类管理功能,dcm4chee在解析时使用的是java提供的多种预设线程池。
对于.NET与java两种系统自带线程池的对比会放到该系列的随后博文中,本篇博文着重介绍dcm4chee中使用的Leader/Follower线程池LF_ThreadPool。
线程池:Leader/Follower ThreadPool
Leader/Follower线程池模型状态切换示意图如下:
在Leader/Follower线程池模式下,线程可处于三种状态:leader、follower、processor。处于leader状态的线程负责响应客户端请求(诸如ServerSocker.accept()监听某个端口),当客户端请求到来时,leader线程会从follower状态的诸多线程中选出新的线程作为leader继续监听客户端请求,自己则放弃leader角色进入到processor状态,开始处理客户端请求的实际操作。
借用58沈剑的总结,Leader/Follower多线程模型有六个关键点:
(1)线程有3种状态:领导leading,处理processing,追随following;
(2)假设共N个线程,其中只有1个leading线程(等待任务),x个processing线程(处理),余下有N-1-x个following线程(空闲);
(3)有一把锁,谁抢到就是leading;
(4)事件/任务来到时,leading线程会对其进行处理,从而转化为processing状态,处理完成之后,又转变为following;
(5)丢失leading后,following会尝试抢锁,抢到则变为leading,否则保持following;
(6)following不干事,就是抢锁,力图成为leading;
Leader Follower相较于传统的线程池的优点是不需要消息队列,其自身具有一定的“智能”,我们参照dcm4chee的LF_ThreadPool的具体代码来看一下:
public void join()
{
log.debug("Thread: " + Thread.currentThread().getName() + " JOIN ThreadPool " + name);