java并发编程笔记(七)——线程池
- new Thread弊端
- 每次new Thread新建对象,性能差
- 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM
- 缺少更多功能,如更多执行、定期执行、线程中断
- 线程池的好处
- 重用存在的线程,减少对象创建、消亡的开销,性能佳
- 可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞
- 提供定时执行、定期执行、单线程、并发数控制等功能
ThreadPoolExecutor
重要核心参数
-
corePoolSize:核心线程数量
-
maximuPoolSize:线程池最大线程数
-
workQueue:阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程产生重大影响
-
keepAliveTime:线程没有任务执行的时候最多保持多久时间终止,比如任务量低于核心线程数的时候,线程需要再等待多久才可以释放掉线程
-
unit:keepAliveTime的时间单位
-
threadFactory:线程工厂,用来创建线程,能够使创建的线程具有相同的优先级,并且是非守护的线程,同时也设置了线程的名称,
-
rejectHandler:当拒绝处理任务时的策略
- 直接抛出异常
- 用调用者所在的线程来执行任务
- 丢弃队列中最靠前的任务来释放线程执行当前任务
- 直接丢弃当前任务
线程池的五种状态
-
RUNNING:能够接受新提交的任务,也能处理阻塞队列中的任务,
-
(pool.shutdown())SHUTDOWN:关闭状态,不能接受新提交的任务,但是能够处理阻塞队列中保存的任务
-
(pool.shutdownNow())STOP:不能接受新的任务,也不能处理阻塞队列中的任务,会中断正在处理中的线程。
-
TIDYING:阻塞队列为空,线程池中的工作线程数为0
-
(pool.terminated()) TERMINATED
线程池的相关方法
-
execute():提交任务,交给线程池执行
-
submit():提交任务,能够返回执行结果 execute + Future
-
shutdown():关闭线程池,等待任务都执行完
-
shutdownNow():关闭线程池,不等待任务执行完
-
getTaskCount():线程池已执行和未执行的任务总数
-
getCompletedTaskCount():已完成的任务数量
-
getPoolSize():线程池当前的线程数量
-
getActiveCount():当前线程池中正在执行任务的线程数量
Executor框架接口
-
Executors.newCachedThreadPool
-
Executors.newFixedThreadPool
-
Executors.newScheduledThreadPool
@Slf4j public class ThreadPoolExample4 { public static void main(String[] args) { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); // executorService.schedule(new Runnable() { // @Override // public void run() { // log.warn("schedule run"); // } // }, 3, TimeUnit.SECONDS); executorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { log.warn("schedule run"); } }, 1, 3, TimeUnit.SECONDS); // executorService.shutdown(); Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { log.warn("timer run"); } }, new Date(), 5 * 1000); } }
-
Executors.newSingleThreadExecutor
线程池的合理配置
- CPU密集型任务,就需要尽量压榨CPU,参考值可以设置为N(cpu) + 1
- IO密集型任务,参考值可以设置为2*N(cpu)