上一篇文章我们说了创建线程的几种方式,按照上一篇文章,我们如果要创建多个线程,是不是就要多写几个实现多线程方式的类呢?要知道我们频繁创建和销毁线程是要耗费大量的资源的,为了减少不必要的资源开销,就有了线程池的出现,其实线程池就是想让我们复用里面的线程;减少不必要的开销。
要了解线程池,就要先了解创建线程池的七大参数的一种。
JUC包下面的 ThreadPoolExecutor类
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
几个参数的作用:
1、corePoolSize: 核心线程数 (保留在池中的线程数,即使它们处于空闲状态)
2、maximumPoolSize: 最大线程数 (线程池能够创建的最多线程数)
3、KeepAliveTime: 空闲线程存活时间
4、unit: KeepAliveTime空闲线程存活时间单位
5、workQueue: 执行任务之前用来保存任务的队列
6、threadFactory: 创建新线程时使用的工厂,一般默认都用 Executors.defaultThreadFactory()
7、handler: 拒绝策列
JDK已经为我们提供创建线程池的工具类了,其实就是为我们填好上面一些参数的方法,它位于Executors类下面。
分别是:
1、newFixedThreadPool - -创建固定线程数的线程池,超出最大线程数就在队列中等待。
2、newSingleThreadExecutor - -创建一个只有一个线程的线程池,任务保证顺序执行。
3、newCacheThreadPool - -创建一个缓存线程池,线程能够复用就复用,不能够就创建新的线程。
4、newSchduledThredPool - - 创建一个一个可以在给定延迟之后运行或定期执行的线程池。
5、newWorkStealingPool - -创建一个维持足够的线程以支持给定并行级别的线程池。
ps:阿里巴巴开发手册不建议我们用上面哪些方法来创建线程池。
一、newFiexdThreadPool
看看源码,我们设定多少个线程数,它就只能有多少个线程数,超出了指定线程数,就添加到等待队列中等待,这个可控制并发线程数量。
我们一次性提交比指定线程数还多的任务,看看它是否会创建新的线程。
实际上它不会创建比指定更多的线程,如果任务数超过线程数,那么其他未能执行的线程就会放进等待队列里面。
运行结果:
二、newSingleThreadPool
源码中的最大线程数何核心线程数都是1,上面的newFixedThreadPool如果将固定线程数改成1,那么它跟newSingleThreadPool没有区别。
创建多个任务,看任务的执行顺序是否有序
从下图可以看到每个任务都是按序执行
三、newCacheThreadPool
在源码中看到,核心线程数为0,最大线程数为为Integer.MAX_VALUE,使用了阻塞队列SynchronsQueue。
创建多个任务
结果看到,它会创建与任务数相等的线程数,因为任务来得太急了。
如果我们让任务休眠一段时间再来,它就会复用当初的线程。
当任务进来的时间慢下来了,线程是可以复用的。
四、newScheduledThreadPool
看源码,最大线程数还是Integer.MAX_VALUE,空闲线程存活时间为0,队列为延迟工作队列。
让它延迟5秒再执行任务
看执行结果,我们可以看到 执行任务的时间可以在指定的延迟时间之后。
五、newWorkStealingPool
源码 ,适合使用在很耗时的操作 ,newWorkStealingPool不是ThreadPoolExecutor的扩展,它是新的线程池类ForkJoinPool的扩展,但是都是在统一的一个Executors类中实现,由于能够合理的使用CPU进行对任务操作(并行操作),所以适合使用在很耗时的任务中