线程池的使用及原理详解

Java中的线程池是运用场景最多的并发框架,几乎所有需要并发执行的程序都可以使用线程池,合理的使用线程池可以降低资源消耗提高响应速度提高线程的可管理性

1.线程池的实现原理

当提交一个新任务到线程池时,线程池的处理流程如下:

线程池判断核心线程是否都在执行任务,如果不是则创建核心线程去执行任务,如果核心线程都在执行任务,线程池会判断任务队列是否已满,如果任务队列没有满,则将新提交的任务存储在任务队列中,如果任务队列满了,线程池会判断线程池中的线程是否都处于工作状态,如果没有则会创建线程池来处理任务,如果满了,则会执行饱和策略。

2.线程池的使用                

我们可以通过ThreadPoolExecutor来创建一个线程池:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {...}

创建一个线程池需要输入几个参数,如下:

corePoolSize:核心线程池数量,在创建线程池之后,线程池默认没有任何线程,只有当任务过来的时候才会创建线程去执行任务,当线程池中的线程数达到corePoolSize后,之后到来的任务会被放入任务队列中。

maximumPoolSize: 线程池允许创建的最大线程数,如果任务队列满了,并且已创建的线程数小于最大线程数,则线程池会创建新的工作线程去执行任务。

keepAliveTime:线程池中的工作线程空闲后,保持存活的时间,如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,keepAliveTime同样会作用于核心线程。

unit:用于指定keepAliveTime参数的时间单位,这是一个枚举,可选的单位有毫秒(MILLISECONDS),分钟(SECONDS) 等。

workQueue:用于保存等待执行的任务的任务队列,通过线程池的execute方法提交的Runnable对象这个参数中。可以选择以下几个阻塞队列:

1).ArrayBlockingQueue:是一个基于数组结构的阻塞队列,此队列按照先进先出的原则对数组进行排序,此队列创建时必须指定大小。

2).LinkedBlockingQueue:是一个基于链表结构的阻塞队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE。

3).SynchronousQueue:一个不存储元素的阻塞队列,而是将直接新建一个线程来执行新来的任务。

threadFactory:线程工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

handler:饱和策略,当队列和线程池都满了,说明线程池处于饱和状态,那么必须采用一种策略来处理新提交的任务,这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。线程池有如下4种处理策略:

1).AbortPolicy:直接抛出异常

2).CallerRunsPolicy:该策略不抛弃任何任务,也不会抛出异常,他不会在线程池中的某个线程中执行任务,而是在调用execute()方法的线程中执行该任务。

3).DiscardOldestPolicy:则会抛弃下一个将会执行的任务,然后尝试重新提交该任务。

4).DiscardPolicy:不处理,丢弃掉。

3.关闭线程池

停止线程池执行主要有两个方法,第一个是shutdown(),第二个是shutdownNow()方法,他们的主要区别是:

调用shutdown()方法,将会把线程池的状态标记为SHUTDOWN,线程池将不会接收任何新的任务,并且会继续执行队列里的任务,直到所有任务执行完成,终止线程池。

调用shutdownNow()方法,将会把线程池的状态标记为STOP,此时线程池也不会接收任何新的任务,并且立即停止正在执行任务的线程,将队列里的任务返回给调用者。

4.合理的配置线程池

要想合理的配置线程池,就要知道任务的特性

任务类型分为CPU密集型IO密集型

性质不同的任务采用不同规模的线程池进行处理,对于CPU密集型的任务可以配置尽可能小的线程,对于IO密集型的任务可以配置尽可能多的线程。

参考资料:《Java并发编程的艺术》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 为加深对线程的理解,首先推荐一篇文章:我是一个线程 线程 进程就是在某种程度上相互隔离、独立运行的程序。和进程一样...
    itcode阅读 1,633评论 0 12
  • Java线程池 一、Executor(执行器)框架 ​ 创建一个新线程是有一定代价的,以为涉及与操作系统的交互...
    thorhill阅读 1,651评论 4 23
  • 1. 线程池的概念 1.1 基本概念 由于线程的生命周期中包括创建、就绪、运行、阻塞、销毁阶段,当我们待处理的任务...
    Java旅行者阅读 1,653评论 0 31
  • 本篇文章讲述Java中的线程池问题,同样适用于Android中的线程池使用。本篇文章参考:Java线程池分析,Ja...
    Ruheng阅读 7,252评论 1 64
  • 目录 从零实现ImageLoader(一)—— 架构从零实现ImageLoader(二)—— 基本实现从零实现Im...
    GavinLi369阅读 1,605评论 0 9

友情链接更多精彩内容