常用线程池主要有4个
SingleThreadExecutor:单线程池,同时只有一个线程在跑
CachedThreadPool():回收线程池,可以重复利用之前创建过的线程,运行线程最大数是Integer.MAX_VALUE
FixedThreadPool():固定大小的线程池,跟回收型线程池类似,只是可以限制同时运行的线程数量
ScheduledExecutorService:除了线程池的特性外,可以实现循环和延迟任务
使用new Thread()的缺陷
1.Java线程机制是抢占性的,new Thread出来的匿名线程难以管理,虽然有优先级方法,效果并不理想,会很混乱,Java线程机制会给每个线程提供时间片,匿名线程多了,影响耗能
2.在java中new Thread在难以管理的情况下,销毁线程的性能是很差的,而线程池服用线程的特性极大的提高了效率和性能
3.new Thread功能单一,没有定时执行,线程中断等功能
SingleThreadExecutor
创建一个单线程的线程池,只有一个线程在工作,单线程串行执行所有任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代,线程池保证所有任务的执行顺序按照任务的提交顺序执行
核心线程数和最大线程数都为1,使用LinkedBlockingQueue阻塞队列换成任务
LinkedBlockingQueue是一个无界缓存队列,当前执行的线程数量达到核心线程数时,剩余的任务会在阻塞队列里面等待,使用此阻塞队列时最大线程数maximumPoolSizes就无效了,每个线程完全独立于其他线程,用户使用独立锁来控制数据的同步,在高并发的情况下可以并行操作队列中的数据
注:这个队列需要注意的是,虽然通常称其为一个无界队列,但是可以人为指定队列大小,默认队列大小为 Integer.MAX_VALUE
FixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
创建固定大小的线程池,每次提交一个任务就创建一个线程,直道线程达到线程池的最大数目,线程池的大小一旦达到最大值,就会保持不变,如果某个线程池因为异常提前结束,那么线程池会补充一个新的线程
核心线程数和最大线程数相等,使用的缓存队列LinkedBlockingQueue
CachedThreadPool
创建一个可缓存的线程池,如果线程池的大小超过了任务需要的数量,那么就会回收空闲部分(60s的期限)的线程,当任务数增加时,线程池能添加新的线程来执行任务,此线程不会对线程池的大小做限制,线程池的大小完全依赖于操作系统能创建的的最大线程数
可以看见构造方法,核心线程数为0,线程数为最大值,任务的缓存队列为SynchronousQueue
SynchronousQueue没有容量,是无缓冲队列,是一个不存储元素的阻塞队列,会直接将任务提交给线程执行,必须等队列中的添加任务被执行后才会继续添加新的任务,拥有公平(FIFO)和非公平(LIFO)策略,非公平策略会导致一些任务永远无法被执行
使用SynchronousQueue阻塞队列一般要求maximumPoolSizes为无界(Integer.MAX_VALUE),避免线程拒绝执行操作
ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素尝试加入ArrayBlockingQueue时会报错
ScheduledExecutorService
创建一个定长的线程池,支持定时及周期性任务执行
创建的时候,可以看到返回的是一个ScheduledThreadPoolExecutor(int)的对象,继续看这个对象
ScheduledThreadPoolExecutor类继承了ThreadPoolExecutor线程池,实现了ScheduledExecutorService接口