面试六、多线程之线程池
1、线程池
1.1、executor接口:只有一个execute()方法
1.2、ExecutorService接口:继承executor,增加了几个重要方法
1.2.1、shutdown():等待正在执行的线程执行完毕,拒绝接受新线程,关闭线程池
1.2.2、shutdownNow():立即关闭线程池和当前正在执行的线程,可能会报错。如果需要等待执行中的线程执行完毕,可调用awaitTermination。
1.2.3、submit():和execute()方法比,多了返回值
1.3、Executors类:提供了6个创建不同线程池的方法
1.3.1、newFixedThreadPool():返回ThreadPoolExecutor,固定线程池中的线程数
1.3.1、newWorkStealingPool():返回ForkJoinPool,
1.3.1、newSingleThreadPool():返回ThreadPoolExecutor,线程池中只有一个线程,新进入的线程进入排队,保证任务的顺序执行
1.3.1、newCachedThreadPool():返回ThreadPoolExecutor,线程池中的线程数随着execute()和submit()方法调用自动创建,如果有空余线程则取已有空闲线程不新建
每60秒回收空闲线程
1.3.1、newSingleThreadScheduledExecutor():返回ScheduledThreadPoolExecutor,
1.3.1、newScheduledThreadPool():返回ScheduledThreadPoolExecutor
1.4、参数:
corePoolSize:核心线程数量
maxmumPoolSize:最大线程数量,核心线程数满时可继续创建线程直到达到最大线程数量
keepAliveTime:线程的空闲时间,当前线程数量大于核心线程数量时,会将超过空闲时间的线程回收
threadFactory:线程工厂,用来创建一个新线程时使用的工程,可以设置线程名称,是否daemon线程
timeunit:空闲时间单位
workQueue:阻塞队列,有4种
ArrayBlockingQueue:基于数组的有界队列,有序,新任务进来排到队列最后,因为有界所以可防止资源耗尽的问题
LinkedBlockingQueue:基于链表的无界队列,当线程数达到corePoolSize后新任务进来会一直存入队列,但不创建线程,即maxmumPoolSize无效
SynchronousQueue:同步不缓存任务的队列,新任务进来直接调度执行,如线程数不够则创建,如已达到maxmumPoolSize,则执行拒绝策略
PriorityBlockingQueue:有优先级的无界队列,通过参数comparator来实现
handler:拒绝策略
CallerRunsPolicy:直接调用被拒绝任务的run方法,如线程池已经shutdown,则抛弃任务
AbortPolicy:直接抛弃任务,并抛出RejectedExecutionExcecption
DiscardPolicy:直接抛弃任务
DiscardOldestPolicy:尝试抛弃最早放入队列的那个任务,并把当前任务加入队列中
自定义拒绝策略,实现RejectedExecutionHandler接口
1.5、线程池运行过程
1、线程池为空
2、任务a进入,校验线程数如小于corePoolSize,则创建新线程执行任务
3、任务a执行完成,线程不会销毁进入阻塞
4、任务b进入,校验线程数如小于corePoolSize,则继续创建新线程执行任务,一直到线程池中线程数达到corePoolSize
5、任务c进入,取线程池中的阻塞线程执行任务,如线程池中所有线程都不在阻塞,则将任务加入workQueue,等待线程执行
6、如果工作队列是无界队列,则可一直将任务塞入队列中等待执行;如工作队列是有界队列,则队列数到限定值后进入队列失败,尝试创建新线程,直到maxmunPoolSize
7、如果线程池线程数到maxmumPoolSize,工作队列也满了,则会执行reject,默认是AbortPolicy(拒绝任务,并抛出异常)
8、超出corePoolSize部分到线程,当空闲时间满足后会销毁
1.6、为什么使用线程池
可以存放线程,将执行完任务的线程阻塞等待唤醒,避免线程频繁的创建销毁
1.7、线程调优
根据需要选择对应的线程:如,需要顺序执行任务则选择SingleThreadExecutor
设置合适的核心线程数:cpu密集性即cpu使用率较高,则可以将核心线程数设置为n+1;如是io密集型即cpu使用率不高则可讲核心线程数设置为2n
设置合适的队列大小:如发送短信,任务量大但是处理效率高,此时可通过设置不大的核心线程数和设置较大的队列数;
如任务数不多但处理效率不高,则可通过设置大的核心线程数和设置较小的队列数,防止线程执行时间过程导致大量任务等待
1.8、动态调整参数
setCorePoolSize:覆盖核心线程数
setMaxmunPoolSize:覆盖最大线程数
注意:设置时如果corePoolSize>maxmumPoolSize,会出现虽然核心线程数增加了但是活跃线程最大是maxmumPoolSize
因为在ThreadPoolExecutor.getTask()方法中会对工作线程数和maxmunPoolSize做一次比较,当工作线程数>maxmumPoolSize时返回空即没有获取到task,
并cas操作工作线程数减一
posted on 2021-08-26 14:54 Iversonstear 阅读(64) 评论(0) 编辑 收藏 举报