1.线程池的优势
(1).降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
(2).提高系统响应速度,当有任务到达时,通过重用已存在的线程,无需等待新线程的创建便能立即执行;
(3).方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且造成CPU过度切换
(4).提供更强大的功能,延时定时线程池。
2.线程池的主要参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
1.corePoolSize(线程池基本大小):当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,指导已创建的线程数大于或者等于corePoolSize时
2.maxinumPoolSize(线程池最大大小):线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maxinumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可以忽略该参数。
3.keepAliveTime(线程存活保持时间)当线程池中的线程数大于核心线程数时,线程的空闲时间如果超过线程存活的时间,那么这个线程就会被销毁,知道线程池中的线程个数小于核心线程数
4.workQueue(任务队列):用于传输和保存等待执行任务的阻塞队列
5.threadFactory(线程工厂):用于创建新线程,threadFactory创建的线程采用Thread newThread(Runnable r);方式,
6.handler(线程饱和策略):当线程池和队列都满了,在加入线程会执行才策略。有四种:
AbortPolicy:丢弃任务,抛出RejectExecutionException异常
CallerRunsPolicy: 这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功。
DiscardPolicy: 直接丢弃任务,无异常
DiscardOldestPolicy: 丢弃队列头部任务
3.线程池流程
如果此时线程池中的数量小于 corePoolSize ,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于 corePoolSize ,但是缓冲队列 workQueue 未满,那么任务被放入缓冲队列。
如果此时线程池中的数量大于 corePoolSize ,缓冲队列 workQueue 满,并且线程池中的数量小于maximumPoolSize ,建新的线程来处理被添加的任务。
如果此时线程池中的数量大于 corePoolSize ,缓冲队列 workQueue 满,并且线程池中的数量等于maximumPoolSize ,那么通过 handler 所指定的策略来处理此任务。
核心线程 corePoolSize 、任务队列 workQueue 、最大线程 maximumPoolSize ,如果三者都满了,使用 handler处理被拒绝的任务。当线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过 keepAliveTime ,线程将被终止。这样,线程池可以动态的调整池中的线程数。
4.线程池为什么需要使用(阻塞)队列?
1.因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成CPU过度切换
2.线程池创建线程添加任务需要获取mainlock这个全局锁,影响并发效率,阻塞队列可以很好的缓冲。
5.线程池为什么要使用阻塞队列而不使用非阻塞队列?
阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。
当队列中有任务时才唤醒对应线程从队列中取出消息执行,使得线程不至于一直占用CPU资源
6.java中提供的线程池
Executors类提供了4种不同的线程池:newCahcedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor
1.newCahcedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务.(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)
2.newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变,适用于负载较重的场景,对当前线程数量进行限制(保证线程数可控,不会造成线程过多,导致系统负载更为严重)
3.newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。
4.newScheduledThreadPool:适用于执行延时或者周期性任务
7.execute()和submit()方法
1.execute(),执行一个任务,没有返回值。
2.submit(),提交一个线程任务,有返回值。