多线程之两种线程池对比
2017-04-21 10:16
169 查看
西城旧梦梦旧人 2017-04-19 22:09
Java的线程池从本质上来说只有两个:ThreadPoolExecutor和Scheduled-ThreadPoolExecutor,这两个类还是父子关系,但是Java为了简化并行计算,还提供了一个Executors的静态类,它可以直接生成多种不同的线程池执行器,比如单线程执行器、带缓冲功能的执行器等,但归根到底还是使ThreadPoolExecutor类或Scheduled-ThreadPoolExecutor类的封装类。
我们首先来看下ThreadPoolExecutor类,先来看下构造函数。
最复杂的构造函数
这个构造函数是ThreadPoolExecutor最完整的构造函数。下面看下这些参数的介绍:
corePoolSize:最小线程数。
线程启动后,在池中保持线程的最小数量。需要说明的是线程数量是逐渐[b]大到corePoolSize值的,[/b]例如corePoolSize被设置为10,而任务数量只有5,则线程池中最多被启动5个线程,而不是一次性启动10个线程。
maximumPoolSize:最大线程数量。
这是池中能够容纳的最大线程容量,如果超出,则使用RejectedExecutionHandler拒绝策略处理。
keepAliveTime:线程最大生命期。
这里的生命期有两个约束条件:一是该参数针对的是超过corePoolSize数量的线程;二是处于非运行状态的线程。也就是说,如果corePoolSize为10,macimumPoolSize为20,此时线程池中有15个线程在运行,一段时间后,其中有3个线程处于等待状态的时间超过了keepAliveTime知道的时间,则结束这3个线程,此时线程池中则还有12个线程正在运行。
unit:时间单位。
这是keepAliveTime的时间单位,可以是纳秒、毫秒、秒、分钟等。
workQuene:任务队列。
当线程池中的线程都处于运行状态,而此时任务数量继续增加,则需要一个容器来容纳这些任务,这就是任务队列。
threadFactory:线程工厂。
定义如何启动一个线程,可以设置线程名称,并且可以确认是否是后台线程等。
handler:拒绝任务处理器。
由于超出线程数量和队列容量而对继续增加的任务进行处理的程序。
线程池的管理是这样的一个过程:首先创建线程池,然后根据任务的数量逐渐将线程增大到corePoolSize数量,如果此时仍有任务增加,则放置到workQuene中,直到workQuene爆满为止,然后继续增加池中的线程数量(增加处理能力),最终达到maximumPoolSize,那如果此时还有任务要进来呢?这就需要handler来处理了,或者丢弃新任务,或者拒绝新任务,或者挤占已有任务等。
在任务队列和线程池都饱和的情况下,一旦有线程处于等待(任务处理完毕,没有新任务增加)状态的时间超过了keepAliveTime,则该线程终止,也就是说池中的线程数量会逐渐降低,直至为corePoolSize数量为止。
现在来通过实际场景来描述一下:在一条生产线上,车间规定是可以有corePoolSize数量的工人,但是生产线刚建立时,工作不多,不需要那么多人。随着工作数量的增加,工人数量也逐渐增加,直至增加到corePoolSize数量为止,此时任务还在增加,那么任务就需要排队!corePoolSize数量的工人马不停蹄的处理任务,新增加的任务按照一定规则放到仓库中(workQuene),一旦任务增加的速度超过了工人处理的能力,也就是说仓库爆满了,车间就需要继续招聘工人(增加线程数),直至工人数量达到maximumPoolSize为止,那如果maximumPoolSize数量的工人都在处理任务,而且仓库又爆满了,新增的任务就是要扔给handler机构去处理,要么丢弃这些新增的任务,要么无视,要么替换掉别的任务。
这样过了一段时间后,任务的数量逐渐减少了,导致一部分的工人处于待工状态,为了减少开支,于是开始辞退工人,知道保持为corePoolSize数量的工人为止,此时即使没有工作,也不会辞退工人。这也是为了保证以后再有任务时能够快速的处理。
看完线程池的概念,我们再来看下Executors提供的几个创建线程池的便捷方法:
newSingleThreadExecutor:单线程池。
顾名思义就是池中只有一个线程在运行,由于是一个线程,当多个任务需要处理的时候,会将他们放到一个无界阻塞队列中逐个处理。实现方法直接看多线程之异步运算。
newCachedThreadPool:缓冲功能的线程池。
建立一个线程池,而且线程数量是没有限制的(不能超过Integer的最大值),增加一个任务既有一个线程处理,或者复用之前空闲的线程,或者启动一个新的线程,但是一旦一个线程在60s内一直是处于等待状态时,则会被终止。这里要注意的是,任务队列使用的是同步阻塞队列,就是说对类中加一个元素,就可以新唤醒一个线程。这种队列没有队列深度的概念。
newFixedThreadPool:固定线程数量的线程池。
在初始化的时候决定线程的最大数量,若任务添加的能力超出了线程的处理能力,则建立阻塞队列容纳多余的任务。可以在源码中看到,它的corePoolSize和maximumPoolSize是相等的,也就是说,最大的线程数是nThreads。如果任务增长速度非常快,超过了队列的容量(Integer的最大值),那么就会按照ThreadPoolExecutor默认的拒绝策略(直接丢弃)来处理。
以上就是Executors的三种线程池执行器,大家在开发的时候可以选择相应的线程池去开发~~
Java的线程池从本质上来说只有两个:ThreadPoolExecutor和Scheduled-ThreadPoolExecutor,这两个类还是父子关系,但是Java为了简化并行计算,还提供了一个Executors的静态类,它可以直接生成多种不同的线程池执行器,比如单线程执行器、带缓冲功能的执行器等,但归根到底还是使ThreadPoolExecutor类或Scheduled-ThreadPoolExecutor类的封装类。
我们首先来看下ThreadPoolExecutor类,先来看下构造函数。
最复杂的构造函数
这个构造函数是ThreadPoolExecutor最完整的构造函数。下面看下这些参数的介绍:
corePoolSize:最小线程数。
线程启动后,在池中保持线程的最小数量。需要说明的是线程数量是逐渐[b]大到corePoolSize值的,[/b]例如corePoolSize被设置为10,而任务数量只有5,则线程池中最多被启动5个线程,而不是一次性启动10个线程。
maximumPoolSize:最大线程数量。
这是池中能够容纳的最大线程容量,如果超出,则使用RejectedExecutionHandler拒绝策略处理。
keepAliveTime:线程最大生命期。
这里的生命期有两个约束条件:一是该参数针对的是超过corePoolSize数量的线程;二是处于非运行状态的线程。也就是说,如果corePoolSize为10,macimumPoolSize为20,此时线程池中有15个线程在运行,一段时间后,其中有3个线程处于等待状态的时间超过了keepAliveTime知道的时间,则结束这3个线程,此时线程池中则还有12个线程正在运行。
unit:时间单位。
这是keepAliveTime的时间单位,可以是纳秒、毫秒、秒、分钟等。
workQuene:任务队列。
当线程池中的线程都处于运行状态,而此时任务数量继续增加,则需要一个容器来容纳这些任务,这就是任务队列。
threadFactory:线程工厂。
定义如何启动一个线程,可以设置线程名称,并且可以确认是否是后台线程等。
handler:拒绝任务处理器。
由于超出线程数量和队列容量而对继续增加的任务进行处理的程序。
线程池的管理是这样的一个过程:首先创建线程池,然后根据任务的数量逐渐将线程增大到corePoolSize数量,如果此时仍有任务增加,则放置到workQuene中,直到workQuene爆满为止,然后继续增加池中的线程数量(增加处理能力),最终达到maximumPoolSize,那如果此时还有任务要进来呢?这就需要handler来处理了,或者丢弃新任务,或者拒绝新任务,或者挤占已有任务等。
在任务队列和线程池都饱和的情况下,一旦有线程处于等待(任务处理完毕,没有新任务增加)状态的时间超过了keepAliveTime,则该线程终止,也就是说池中的线程数量会逐渐降低,直至为corePoolSize数量为止。
现在来通过实际场景来描述一下:在一条生产线上,车间规定是可以有corePoolSize数量的工人,但是生产线刚建立时,工作不多,不需要那么多人。随着工作数量的增加,工人数量也逐渐增加,直至增加到corePoolSize数量为止,此时任务还在增加,那么任务就需要排队!corePoolSize数量的工人马不停蹄的处理任务,新增加的任务按照一定规则放到仓库中(workQuene),一旦任务增加的速度超过了工人处理的能力,也就是说仓库爆满了,车间就需要继续招聘工人(增加线程数),直至工人数量达到maximumPoolSize为止,那如果maximumPoolSize数量的工人都在处理任务,而且仓库又爆满了,新增的任务就是要扔给handler机构去处理,要么丢弃这些新增的任务,要么无视,要么替换掉别的任务。
这样过了一段时间后,任务的数量逐渐减少了,导致一部分的工人处于待工状态,为了减少开支,于是开始辞退工人,知道保持为corePoolSize数量的工人为止,此时即使没有工作,也不会辞退工人。这也是为了保证以后再有任务时能够快速的处理。
看完线程池的概念,我们再来看下Executors提供的几个创建线程池的便捷方法:
newSingleThreadExecutor:单线程池。
顾名思义就是池中只有一个线程在运行,由于是一个线程,当多个任务需要处理的时候,会将他们放到一个无界阻塞队列中逐个处理。实现方法直接看多线程之异步运算。
newCachedThreadPool:缓冲功能的线程池。
建立一个线程池,而且线程数量是没有限制的(不能超过Integer的最大值),增加一个任务既有一个线程处理,或者复用之前空闲的线程,或者启动一个新的线程,但是一旦一个线程在60s内一直是处于等待状态时,则会被终止。这里要注意的是,任务队列使用的是同步阻塞队列,就是说对类中加一个元素,就可以新唤醒一个线程。这种队列没有队列深度的概念。
newFixedThreadPool:固定线程数量的线程池。
在初始化的时候决定线程的最大数量,若任务添加的能力超出了线程的处理能力,则建立阻塞队列容纳多余的任务。可以在源码中看到,它的corePoolSize和maximumPoolSize是相等的,也就是说,最大的线程数是nThreads。如果任务增长速度非常快,超过了队列的容量(Integer的最大值),那么就会按照ThreadPoolExecutor默认的拒绝策略(直接丢弃)来处理。
以上就是Executors的三种线程池执行器,大家在开发的时候可以选择相应的线程池去开发~~
相关文章推荐
- 多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比
- Java多线程13:读写锁和两种同步方式的对比
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- java多线程之:Java中的ReentrantLock和synchronized两种锁定机制的对比 (转载)
- Java两种方式实现多线程对比
- Java创建多线程的两种方式对比
- 多线程两种方式的对比
- Android通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- Java创建多线程的两种方式对比
- Java多线程13:读写锁和两种同步方式的对比
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- 黑马程序员--04.多线程--03.【创建线程两种方法的对比】【多线程卖票案例设计】
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比--转载
- 多线程两种方式对比与区别
- 黑马程序员--Java学习笔记之多线程(自定义线程的两种方式对比、线程状态、线程安全)
- Android通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- java多线程学习二:两种实现多线程方式的对比
- Java中两种实现多线程方式的对比分析