1.线程池是什么
线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这避免了在处理短时间任务时创建与销毁线程的代价
2.使用Excutors创建线程池的方法
Java里面的线程池的顶级接口时是Executor,Executor并不是一个线程池,而是一个执行线程的工具,真正的线程池是ExecutorService
(1) Executors.newFixedThreadPool(100);
创建固定大小的线程池
(2)Executors.newSingleThreadExecutor();
创建只有一个线程的线程池
(3) Executors.newCachedThreadPool();
创建一个不限线程数上限的线程池,任何提交的任务都将立即执行
(4) 对于服务器端需要长期运行的程序,创建线程池应该使用ThreadPoolExecutor
的构造方法
构造方法参数列表;
- corePoolSize: 线程池核心线程数
- maximumPoolSize:线程池最大数
- keepAliveTime: 空闲线程存活时间
- unit: 时间单位
- workQueue: 线程池所使用的缓冲队列
- threadFactory:线程池创建线程使用的工厂
- handler: 线程池对拒绝任务的处理策略
3.线程池4大特性
- 当池中正在运行的线程数(包括空闲线程)小于corePoolSize时,新建线程执行任务
- 当池中正在运行的线程数大于等于corePoolSize时,新插入的任务进入workQueue排队,等待空闲线程来执行
- 当队列里的任务数达到上限,并且池中正在运行的线程数小于maximunPoolSize,对于新加入的任务,新建线程
- 当队列里的任务数达到上限,并且池中正在运行的线程数等于maximunPoolSize,对于新加入的任务,执行拒绝策略(线程池默认的拒绝策略时抛异常)
4.线程池的种类
(1)newCachedThreadPool:核心线程数为0,最大线程数为Integer.MAX_VALUE
- 作用:创建按一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的ThreadFactory创建新线程
- 特征:线程池中数量没有固定,可达到最大值;空闲线程的存活时间是60,线程池中的线程可进行缓存重复利用和回收;当线程池中没有可用线程时,会重新创建一个线程;工作队列是SynchronousQueue
- 创建方式:
Exectors.newCachedThreadPool();
(2)newFixedThreadPool:核心线程数与最大线程数均为指定的n Threads;空闲线程的空闲时间是0;工作队列是无界队列
- 作用:创建一个可重用固定线程数的线程数,以共享的无界队列方式来运行这些线程
- 特征:线程池中的数量处于一定的量,可以很好的控制线程的并发量;线程可以重复被使用,在显示关闭之前,都将一直存在;超出一定量的线程被提交时需要在队列中等待
- 创建方式:
(a)Executors.newFixedThreadPool(int nThreads);//nThreads为线程的数量
(b) Executors.newFixedThreadPool(int nThreads,ThreadFactory threadFactory);//nThreads为线程的数量,threadFactory创建线程的工厂方式
(3)newSingleThreadExecutor:核心线程数与最大线程数均为1;工作队列是无界队列
- 作用:创建一个使用单个worker线程的Executor,以队列方式来运行该线程(若在关闭前的执行期间出现失败而终止了此单个线程,如需要,一个新线程将代替它执行后续的任务);可保证顺序的执行各个任务,并且在任意给定的时间不会有多个线程是活动的
- 特征:线程池中最多执行1个线程,之后提交的线程活动将会排在队列中依次执行
- 创建方式:
(a)Executors.newSingleThreadExecutor() ;
(b)Executors.newSingleThreadExecutor(ThreadFactory threadFactory);// threadFactory创建线程的工厂方式
(4)newScheduledThreadPool:指定核心线程数corePoolSize;最大线程数是Integer.MAX_VALUE
;DelayedWorkQueue:任务队列会根据任务延时时间的优先级进行执行
- 作用:创建一个线程池,可安排在给定延迟后运行命令或者定期的执行
- 特征:线程池中具有指定数量的线程,即便是空线程也将保留;可定时或者延迟执行线程活动
- 创建方式:
(a)Executors.newScheduledThreadPool(int corePoolSize);// corePoolSize线程的个数
(b)newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);// corePoolSize线程的个数,threadFactory创建线程的工厂
(5)newSingleThreadScheduledExecutor
- 作用:创建一个单线程执行程序,可以安排在给定延迟后运行命令或者定期的执行
- 特征:线程池中最多执行1个线程,之后提交的线程活动将会排在队列中依次执行;可定时或者延迟执行线程活动
- 创建方式:
(a)Executors.newSingleThreadScheduledExecutor() ;
(b)Executors.newSingleThreadScheduledExecutor(ThreadFactory threadFactory);//threadFactory创建线程的工厂
5.工作队列
(1)SynchronousQueue:直接提交
工作队列的默认选项,将任务直接提交给线程而不保持;如果不存在可用于立即运行任务的线程,则试图将任务加入队列将失败,会构造一个新线程
- 特点:可以避免在处理可能具有内部依赖性的请求集时出现锁;直接提交通常要求无界maximumPoolSizes以避免拒绝新提交的任务;当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程池具有增长的可能性
(2)ArrayBlockingQueue:有界队列
当与有限的maximumPoolSizes一起使用时,有界队列有助于防止资源耗尽,但是调整和控制会更加困难
队列大小和最大池大小相互权衡:
- 使用大队列和小池可以最大程度地减少CPU使用率,操作系统资源和上下文切换开销,但可能会降低吞吐量
- 如果任务频繁阻塞,系统可能可以为非预定的更多线程安排时间
- 使用小队列通常需要更大的池,会使CPU繁忙,遇到不可接受的调度开销,这也会降低吞吐量
(3)LinkedBlockingQueue:无界队列
在所有核心线程都忙时,新任务在队列中等待,因此创建corePoolSize线程即可;当每个任务完全独立于其他任务时,不会相互影响
- 特点:在网页服务器中,对消除短暂的突发请求很有用;当命令请求到达速度比其处理速度更快时,工作队列无限制增长
6.拒绝策略
(1)AbortPolicy:处理程序遭到拒绝将抛出运行时异常:RejectedExecutionException
(2)DiscardPolicy:不能执行的任务将被删除
(3)DiscardOldestPolicy:如果执行程序没有关闭,则位于工作队列头部的任务将被删除,然后重新执行程序(若再次失败,重复此过程)
(4)CallerRunsPolicy:线程调用运行该任务的execute本身,提供简单的反馈控制机制,能够减缓新任务的提交速度
7.使用线程池的优点
- 重用线程池的线程,避免因为线程的创建和销毁锁所带来的性能开销
- 有效控制线程池的最大并发数,避免大量的线程之间因抢占系统资源而阻塞
- 能够对线程进行简单的管理,并提供特定的操作:定时、定期、单线程、并发数控制等功能
参考链接:https://blog.csdn.net/JAck_chen0309/article/details/105250643