从JDK1.5开始,Java API提供了Executor框架,创建不同的线程池。有单线程池、数目固定的线程池、缓存线程池。
Executors线程池工厂提供了一些创建不同特性线程池ThreadPoolExecutor的方法,它们都返回ExecutorService对象:
- Executors.newSingleThreadPool()
- Executors.newFixedThreadPool(int size):定长线程池,可控制线程最大并发数,超出的线程在队列中等待。
- Executors.newCachedTheadPool():适合很多生存期短的任务,空闲线程会在指定时间内被回收。
- Executors.newScheduledThreadPool():定长线程池,支持定时及周期性任务执行
它们内部都是封装了ThreadPoolExecutor:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 15, TimeUnit.SECONDS,new ArrayBlockingQueue(5), new ThreadPoolExecutor.CallerRunsPolicy());
线程池超载后的拒绝策略
池中的线程用光,等待队列也已排满。
扩展线程池
ThreadPoolExecutor提供了用于扩展的接口,比如要监控每个任务执行的开始和结束时间。
打印异常堆栈是排查问题的指南针,用线程池的execte()方法替换submit()方法,可以进而继承ThreadPoolExecutor来扩展出自己的TreaceThreadPoolExecutor。
Guava中扩展的线程池:
- MoreExecutors.directExecutor() :将任务在调用线程中执行。
- 将普通线程池转为Daemon线程池。
- 对Future模式扩展。
估算线程池大小
threadsSize=cpu数量*cpu使用率*(1+等待时间/计算时间)
Fork/Join线程池
分而治之的思想,例如MapReduce,将大任务划分为小任务合成为最终结果。
ForkJoinPool线程池接受提交ForkJoinTask,ForkJoinTask对象可以调用fork()来分叉出小任务。