java线程池类图_java中常见的六种线程池详解
之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的⼏种线程池,以及在jdk7 加⼊的ForkJoin 新型线程池
⾸先我们列出Java 中的六种线程池如下
线程池名称
描述
FixedThreadPool
核⼼线程数与最⼤线程数相同
SingleThreadExecutor
⼀个线程的线程池
CachedThreadPool
核⼼线程为0,最⼤线程数为Integer. MAX_VALUE
ScheduledThreadPool
指定核⼼线程数的定时线程池
SingleThreadScheduledExecutor
单例的定时线程池
ForkJoinPool
JDK 7 新加⼊的⼀种线程池
在了解集中线程池时我们先来熟悉⼀下主要⼏个类的关系,ThreadPoolExecutor 的类图,以及 Executors 的主要⽅法:
上⾯看到的类图,⽅便帮助下⾯的理解和查看,我们可以看到⼀个核⼼类 ExecutorService , 这是我们线程池都实现的基类,我们接下来说的都是它的实现类。
FixedThreadPool
FixedThreadPool 线程池的特点是它的核⼼线程数和最⼤线程数⼀样,我们可以看它的实现代码在
Executors#newFixedThreadPool(int) 中,如下:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
我们可以看到⽅法内创建线程调⽤的实际是 ThreadPoolExecutor 类,这是线程池的核⼼执⾏器,传⼊的 nThread 参数作为核⼼线程数和最⼤线程数传⼊,队列采⽤了⼀个链表结构的有界队列。
这种线程池我们可以看作是固定线程数的线程池,它只有在开始初始化的时候线程数会从0开始创建,但是创建好后就不再销毁,⽽是全部作为常驻线程池,这⾥如果对线程池参数不理解的可以看之前⽂章 《解释线程池各个参数的含义》。
java线程池创建的四种对于这种线程池他的第三个和第四个参数是没意义,它们是空闲线程存活时间,这⾥都是常驻不存在销毁,当线程处理不了时会加⼊到阻塞队列,这是⼀个链表结构的有界阻塞队列,最⼤长度是Integer. MAX_VALUE
SingleThreadExecutor
SingleThreadExecutor 线程的特点是它的核⼼线程数和最⼤线程数均为1,我们也可以将其任务是⼀
个单例线程池,它的实现代码是Executors#newSingleThreadExcutor() , 如下:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), threadFactory)); }
上述代码中我们发现它有⼀个重载函数,传⼊了⼀个ThreadFactory 的参数,⼀般在我们开发中会传⼊我们⾃定义的线程创建⼯⼚,如果不传⼊则会调⽤默认的线程⼯⼚
我们可以看到它与 FixedThreadPool 线程池的区别仅仅是核⼼线程数和最⼤线程数改为了1,也就是说不管任务多少,它只会有唯⼀的⼀个线程去执⾏
如果在执⾏过程中发⽣异常等导致线程销毁,线程池也会重新创建⼀个线程来执⾏后续的任务
这种线程池⾮常适合所有任务都需要按被提交的顺序来执⾏的场景,是个单线程的串⾏。
CachedThreadPool
cachedThreadPool 线程池的特点是它的常驻核⼼线程数为0,正如其名字⼀样,它所有的县城都是临时的创建,关于它的实现在Executors#newCachedThreadPool() 中,代码如下:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new
SynchronousQueue(), threadFactory); }
从上述代码中我们可以看到 CachedThreadPool 线程池中,最⼤线程数为 Integer.MAX_VALUE , 意味着他的线程数⼏乎可以⽆限增加。
因为创建的线程都是临时线程,所以他们都会被销毁,这⾥空闲 线程销毁时间是60秒,也就是说当线程在60秒内没有任务执⾏则销毁
这⾥我们需要注意点,它使⽤了 SynchronousQueue 的⼀个阻塞队列来存储任务,这个队列是⽆法存储的,因为他的容量为0,它只负责对任务的传递和中转,效率会更⾼,因为核⼼线程都为0,这个队列如果存储任务不存在意义。
ScheduledThreadPool
ScheduledThreadPool 线程池是⽀持定时或者周期性执⾏任务,他的创建代码 wSchedsuledThreadPool(int) 中,如下所⽰:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); }
我们发现这⾥调⽤了 ScheduledThreadPoolExecutor 这个类的构造函数,进⼀步查看发现 ScheduledThreadPoolExecutor 类是⼀个继承了 ThreadPoolExecutor 的,同时实现了 ScheduledExecutorService 接⼝,我们看到它的⼏个构造函数都是调⽤⽗类ThreadPoolExecutor 的构造函数
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); } public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory); } public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) { super(corePoolSize,
Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), handler); } public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler); }
从上⾯代码我们可以看到和其他线程池创建并没有差异,只是这⾥的任务队列是 DelayedWorkQueue 关于阻塞丢列我们下篇⽂章专门说,这⾥我们先创建⼀个周期性的线程池来看⼀下
public static void main(String[] args) { ScheduledExecutorService service = wScheduledThreadPool(5); // 1. 延迟⼀定时间执⾏⼀次 service.schedule(() ->{ System.out.println("schedule ==> 云栖简码-line"); },2, TimeUnit.SECONDS); // 2. 按照固定频率周期执⾏ service.scheduleAtFixedRate(() ->{ System.out.println("scheduleAtFixedRate ==> 云栖简码-line"); },2,3,TimeUnit.SECONDS); //3. 按照固定频率周期执⾏ service.scheduleWithFixedDelay(() -> {
System.out.println("scheduleWithFixedDelay ==> 云栖简码-line"); },2,5,TimeUnit.SECONDS); }
上⾯代码是我们简单创建了 newScheduledThreadPool ,同时演⽰了⾥⾯的三个核⼼⽅法,⾸先看执⾏的结果:
⾸先我们看第⼀个⽅法 schedule , 它有三个参数,第⼀个参数是线程任务,第⼆个delay 表⽰任务执⾏延迟时长,第三个unit 表⽰延迟时间的单位,如上⾯代码所⽰就是延迟两秒后执⾏任务
public ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit);
第⼆个⽅法是 scheduleAtFixedRate 如下, 它有四个参数,command 参数表⽰执⾏的线程任务 ,initialDelay 参数表⽰第⼀次执⾏的延迟时间,period 参数表⽰第⼀次执⾏之后按照多久⼀次的频率来执⾏,最后⼀个参数是时间单位。如上⾯案例代码所⽰,表⽰两秒后执⾏第⼀次,之后按每隔三秒执⾏⼀次
public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);<.........>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论