之前咱们介绍了线程池的四种回绝策略,理解了线程池参数的含意,那么明天咱们来聊聊Java 中常见的几种线程池,以及在jdk7 退出的 ForkJoin 新型线程池首先咱们列出Java 中的六种线程池如下线程池名称形容FixedThreadPool外围线程数与最大线程数雷同SingleThreadExecutor一个线程的线程池CachedThreadPool外围线程为0,最大线程数为Integer. MAX_VALUEScheduledThreadPool指定外围线程数的定时线程池SingleThreadScheduledExecutor单例的定时线程池ForkJoinPoolJDK 7 新退出的一种线程池在理解集中线程池时咱们先来相熟一下次要几个类的关系,ThreadPoolExecutor 的类图,以及 Executors 的次要办法:
下面看到的类图,不便帮忙上面的了解和查看,咱们能够看到一个外围类 ExecutorService , 这是咱们线程池都实现的基类,咱们接下来说的都是它的实现类。FixedThreadPoolFixedThreadPool 线程池的特点是它的外围线程数和最大线程数一样,咱们能够看它的实现代码在 Executors#newFixedThreadPool(int) 中,如下: public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }咱们能够看到办法内创立线程调用的理论是 ThreadPoolExecutor 类,这是线程池的外围执行器,传入的 nThread 参数作为外围线程数和最大线程数传入,队列采纳了一个链表构造的有界队列。这种线程池咱们能够看作是固定线程数的线程池,它只有在开始初始化的时候线程数会从0开始创立,然而创立好后就不再销毁,而是全副作为常驻线程池,这里如果对线程池参数不了解的能够看之前文章 《解释线程池各个参数的含意》。对于这种线程池他的第三个和第四个参数是没意义,它们是闲暇线程存活工夫,这里都是常驻不存在销毁,当线程解决不了时会退出到阻塞队列,这是一个链表构造的有界阻塞队列,最大长度是Integer. MAX_VALUESingleThreadExecutorSingleThreadExecutor 线程的特点是它的外围线程数和最大线程数均为1,咱们也能够将其工作是一个单例线程池,它的实现代码是Executors#newSingleThreadExcutor() , 如下: public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }上述代码中咱们发现它有一个重载函数,传入了一个ThreadFactory 的参数,个别在咱们开发中会传入咱们自定义的线程创立工厂,如果不传入则会调用默认的线程工厂咱们能够看到它与 FixedThreadPool 线程池的区别仅仅是外围线程数和最大线程数改为了1,也就是说不论工作多少,它只会有惟一的一个线程去执行如果在执行过程中产生异样等导致线程销毁,线程池也会从新创立一个线程来执行后续的工作这种线程池非常适合所有工作都须要按被提交的程序来执行的场景,是个单线程的串行。CachedThreadPoolcachedThreadPool 线程池的特点是它的常驻外围线程数为0,正如其名字一样,它所有的县城都是长期的创立,对于它的实现在 Executors#newCachedThreadPool() 中,代码如下: public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }从上述代码中咱们能够看到 CachedThreadPool 线程池中,最大线程数为 Integer.MAX_VALUE , 意味着他的线程数简直能够有限减少。因为创立的线程都是长期线程,所以他们都会被销毁,这里闲暇 线程销毁工夫是60秒,也就是说当线程在60秒内没有工作执行则销毁这里咱们须要留神点,它应用了 SynchronousQueue 的一个阻塞队列来存储工作,这个队列是无奈存储的,因为他的容量为0,它只负责对工作的传递和直达,效率会更高,因为外围线程都为0,这个队列如果存储工作不存在意义。ScheduledThreadPoolScheduledThreadPool 线程池是反对定时或者周期性执行工作,他的创立代码 Executors.newSchedsuledThreadPool(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 = Executors.newScheduledThreadPool(5); // 1. 提早肯定工夫执行一次 service.schedule(() ->{ System.out.println("schedule ==> 云栖简码-i-code.online"); },2, TimeUnit.SECONDS); // 2. 依照固定频率周期执行 service.scheduleAtFixedRate(() ->{ System.out.println("scheduleAtFixedRate ==> 云栖简码-i-code.online"); },2,3,TimeUnit.SECONDS); //3. 依照固定频率周期执行 service.scheduleWithFixedDelay(() -> { System.out.println("scheduleWithFixedDelay ==> 云栖简码-i-code.online"); },2,5,TimeUnit.SECONDS); }下面代码是咱们简略创立了 newScheduledThreadPool ,同时演示了外面的三个外围办法,首先看执行的后果:
...