重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要讲解了“什么是线程池”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是线程池”吧!
创新互联建站长期为1000多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为东兴企业提供专业的成都做网站、成都网站建设,东兴网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。
(I:代表接口,C:代表实现类)I:Executor I:ExecutorService C:AbstractExecutorService C:ThreadPoolExecutor
该类的主要构造函数如下:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueueworkQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
corePoolSize:核心线程池的大小。如果核心线程池有空闲位置,新的任务进来就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。
maximunPoolSize:最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。
keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。
unit:时间单位,和keepAliveTime配合使用。
workQueue: 缓存队列,用来存放等待被执行的任务,有以下取值:
1、ArrayBlockingQueue; 有界阻塞队列,详见文章:ArrayBlockingQueue详解
2、LinkedBlockingQueue; 无界阻塞队列,详见文章:LinkedBlockingQueue详解
3、SynchronousQueue; 无缓冲阻塞队列 ,详见文章:SynchronousQueue详解
threadFactory:线程工厂,用来创建线程,默认new Executors.DefaultThreadFactory();
handler: 线程拒绝策略。当创建的线程超出maximumPoolSize值,且缓冲队列已满时,对新提交任务的处理策略,有以下4种取值,我们结合代码分析
1、ThreadPoolExecutor.AbortPolicy 无视任务(也就是丢弃任务),并通过抛异常告知调用者“我拒绝接收新任务”
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //这里直接抛出异常,可理解为:无视任务(也就是丢弃任务),并通过抛异常告知调用者“我拒绝接收新任务” throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }
2、ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不做任何处理。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //这里是空实现,也就是丢弃任务,不作任何的处理 //这会导致:虽然此策略被触发,但调用者根本不知道它提交进来的任务,最终到底有没有被执行 }
3、ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,尝试执行新任务。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { //判断线程池是否被关闭了 e.getQueue().poll();//丢弃队列最前面的任务 e.execute(r); //尝试执行新任务 } }
4、ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { //判断线程池是否被关闭了 r.run(); //调用线程直接调用run()方法,执行其代码逻辑 } }
基于ThreadPoolExecutor 的构造参数如此之多,JDK为我们提供了Executors类,通过它我们可以简单的创建出四种类型的线程池,一般场景下够用了。
1.3.1、固定大小线程池
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor( nThreads, // corePoolSize nThreads,// maximumPoolSize 0L, TimeUnit.MILLISECONDS,// keepAliveTime=0秒 new LinkedBlockingQueue()// 利用无界阻塞队列 ); }
参数:corePoolSize = 固定值,maximumPoolSize = 固定值,keepAliveTime = 0秒 ,workQueue = LinkedBlockingQueue 无界阻塞队列
分析:
1、corePoolSize 和 maximumPoolSize 都为 nThreads 一个固定值,说明此线程池中都是核心线程,keepAliveTime为非核心线程空闲时间,该线程池中不存在非核心线程,所以参数keepAliveTime在此处无效;
2、new LinkedBlockingQueue
3、缺点:因为用的是无界队列,所以当 nThreads 个线程一直被占用的情况下,同时又不断的有新任务进来,就有可能导致OOM问题;
1.3.2、单个线程的线程池
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, // corePoolSize,maximumPoolSize 0L, TimeUnit.MILLISECONDS,// keepAliveTime=0秒 new LinkedBlockingQueue())// 利用无界阻塞队列 ); }
参数:corePoolSize = 1,maximumPoolSize = 1,keepAliveTime = 0秒 ,workQueue = LinkedBlockingQueue 无界阻塞队列
分析:
1、corePoolSize 和 maximumPoolSize 都为1,此线程池只有一个核心线程,同上,参数keepAliveTime在此处无效;
2、new LinkedBlockingQueue
3、缺点:因为用的是无界队列,所以当核心线程一直被占用的情况下,同时又不断的有新任务进来,就有可能导致OOM问题;
4、有没有注意到,这里为什么用了一个FinalizableDelegatedExecutorService类呢?
见文章:关于newSingleThreadExecutor中的FinalizableDelegatedExecutorService源码分析
1.3.3、缓存线程池
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE,// corePoolSize,maximumPoolSize 60L, TimeUnit.SECONDS,// keepAliveTime=60秒 new SynchronousQueue());// 同步阻塞队列 }
参数:corePoolSize = 0,maximumPoolSize = 无限大,keepAliveTime = 60秒(重要) ,workQueue = SynchronousQueue 无缓冲阻塞队列
分析:一个可以根据需要创建线程的线程池,此线程池中所有线程都为非核心线程,且最大空闲时间为60秒,最多可以创建Integer.MAX_VALUE 个线程(2^31次方,21亿多,可以视为无限);SynchronousQueue 为无缓冲阻塞队列,也就是此队列里不会缓冲新的任务,有新任务进来时,如果无空闲线程,就会新创建一个线程;如果有空闲线程,就会使用空闲线程;所以此线程池适合执行一些执行周期短的任务。
感谢各位的阅读,以上就是“什么是线程池”的内容了,经过本文的学习后,相信大家对什么是线程池这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!