0 摘要
介绍了线程池的基本概念和基本用法,重点讲解了ThreadPoolExecutor这个类,以及里面7个参数的配置建议。
1 为什么不new Thread
- 每次new新建线程的时候,性能差
- 线程缺乏统一的管理
- 缺少更多的功能,如线程的调度,如定期执行、线程中断等功能
- Thread里的方法在实际场景中使用复杂,直接操作这些方法容易出错
- ·实际中并不推荐使用这样的方式来使用线程
2 线程池的好处
- 重用存在的线程,减少对象的创建、消亡的开销
- 可有效的控制最大并发线程数,提高线程的系统的资源利用率,同时可以避免过多的资源竞争,避免堵塞
- 提供定时执行、定期执行、单线程、并发数控制功能
3 线程池-ThreadPoolExecutor
//构造函数(参数最多的一个) ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
- corePoolSize:核心线程数量 //如果运行的线程数小于这个数量,直接会创建新的线程来处理任务,即使线程池中其他线程是空闲的
- maximumPoolSize:线程最大线程数 //如果运行的线程数大于corePoolSize小于maximumPoolSize,只有当workQueue满的时候,采取创建新的线程
- workQueue:阻塞队列,存储等待执行的任务的队列 //如果corePoolSize等于maximumPoolSize,此时线程池大小固定,如果阻塞队列没满的时候,会将任务放进队列,等待其他有空闲的线程来执行,如果此时,线程已经满了,则会根据RejectedExecutionHandle任务处理策略来对任务进行处理。
- keepAliveTime:线程没有任务执行的时候最多保持多久时间终止,这里指的是核心线程(corePoolSize的数量)
- TimeUmit:keepAliveTime的单位
- ThreadFactory:线程工厂,用来创建线程,当使用默认的线程工厂的时候会创建的线程会具有同等的优先级和默认的线程名称
- RejectedExecutionHandle:当拒绝任务处理时的策略,当前面的workQueue满了,且此时线程池里面没有空闲的线程。如果仍然在提交任务。那么就需要采取一些策略来处理这些任务。默认的策略是直接抛出异常
线程池的重点在于上面7个参数的选择
线程池实例的方法:
- execute():提交任务
- submit():提交任务,返回执行的结果
- shutdown():关闭线程池,会等待任务的完成
- shutdownnow():关闭任务,不等待任务的完成
线程池实例的监控:
- getTaskCount():线程池已经执行的和未执行的任务总数
- getCompletedTaskCount():已完成的任务数
- getPoolSize():线程池当前的线程数
- getActiveCount():当前线程中正在执行的任务的线程数量
4 线程池-Executor接口
//1.创建一个可缓存的线程,如果没有可回收的就创建新的线程 Executors.newCachedThreadPool(); //2.创建了一个定长的线程池 Executors.newFixedThreadPool(nThreads); //3.创建了定长的线程池,支持定时和执行周期,增加了调度的功能 Executors.newScheduledThreadPool(corePoolSize); //4.创建一个唯一的线程来执行任务 Executors.newSingleThreadExecutor();
//实际都是调用了ThreadPoolExecutor来完成工作
利用Executors框架生成的线程池,使用方便(已经帮你把上面提到的七个参数预先设定好了),但是缺点是少了ThreadPoolExecutor类中很多其他的方法,例如线程池实例监控的方法。
5 小结
总结了线程池的一些基本概念和用法,线程池好用,但是一定要根据实际场景来使用。最后注意使用后,一定要记得关闭。
2019-05-21 21:14:11