“线程池”顾名思义,就是存放线程的池子,这个池子可以存放多少线程取决于采用哪种线程池,取决于有多少并发线程,有多少计算机的硬件资源。
线程池最主要的工作在于控制运行线程的数量,从而做到线程复用、控制最大并发数量、管理线程。其具体的优势在于:
线程池继承结构图:
jdk自带创建线程池的四种常见方式:
源码:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } | | | | | | | | | | | | V V V V V V V V V V V V public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, | | new DelayedWorkQueue()); } | | V V //ScheduledThreadPoolExecutor继承了ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
注意:
ThreadPoolExecutor对构造函数进行了重载,实际内部使用了7个参数:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { ..............//已省略 参数合法校验 ..............//已省略 参数赋值 }
线程池具体工作流程:
当线程池的阻塞队列满了同时线程池中线程数量达到了最大maximumPoolSize时,线程池将会启动相应的拒绝策略来拒绝请求任务。
4种拒绝策略具体为:
注意: 以上4种拒绝策略均实现了RejectedExecutionHandler接口
实际开发中不允许使用内置的线程池:必须明确地通过 ThreadPoolExecutor 方式,指定相应的线程池参数创建自定义线程或者使用其它框架提供的线程池。因为内置线程池的第五个参数阻塞队列允许的请求队列长度为 Integer.MAX_VALUE (从上面的源码上可以看出),可能造成大量请求堆积,导致OOM: 阿里巴巴规范中指出不能使用Executors去创建:
自定义线程池:使用不同的拒绝策略:
package com.raicho.mianshi.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author: Raicho * @Description: 自定义线程池的各个参数 * @program: mianshi * @create: 2020-08-12 10:44 **/ public class CustomThreadPool { public static void main(String[] args) { ExecutorService executorService = new ThreadPoolExecutor( 2, 5, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), // new ThreadPoolExecutor.AbortPolicy() new ThreadPoolExecutor.CallerRunsPolicy() // 注意使用该拒绝策略,可能会回退给main线程执行 // new ThreadPoolExecutor.DiscardOldestPolicy() //new ThreadPoolExecutor.DiscardPolicy() ); try { for (int i = 0; i < 9; i++) { executorService.submit(() -> { System.out.println(Thread.currentThread().getName() + ": 执行任务"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } }); } } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); } } }
线程池合理配置线程数量需要考虑业务具体是CPU密集型还是IO密集型:
CPU密集型任务配置应该尽可能少的线程数量,一般公式为:
CPU核数 + 1个线程的线程池
所以在IO密集型任务中使用多线程可以大大加速程序运行:
CPU核数 / (1 - 阻塞系数) 阻塞系数在0.8-0.9 CPU核数 * 2
原文链接:https://www.cnblogs.com/lzhdonald/p/13490680.html