一:为什么使用线程池
1.1:降低资源的消耗
通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
1.2:提高响应速度
因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行异步任务
1.3:提高线程的可管理性
线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配
二:使用ThreadPoolExecutor创建线程池
使用ThreadPoolExecutor创建线程池之前,我们首先看这七大参数的含义
- corePoolSize:核心线程数,线程池创建好以后就准备就绪执行任务
- maximumPoolSize:线程池最大线程数量,控制线程资源
- keepAliveTime:存活时间,如果当前线程数量大于corePoolSize数量,当线程空闲时间大于指定的keepAliveTime,就会释放空闲的线程(maximumPoolSize-corePoolSize)
- TimeUnit:时间单位,小时,分钟,秒等
- workQueue:阻塞队列,如果有很多任务,就会将目前多于的任务放到阻塞队列中,只要有线程空闲,就会去队列里面取出新的任务继续执行。
- threadFactory:线程的创建工厂
- handler:如果队列满了,按照我们指定的拒绝策略拒绝执行任务
2.1ThreadPoolExecutor线程创建
ThreadPoolExecutor pool=new ThreadPoolExecutor(5,
100,10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
阻塞队列:
拒绝策略:
2.2工作顺序
- 1:线程池创建,准备好core数量的核心线程,准备接收任务
- 2:core满了,就将再进来的任务放入阻塞队列中,空闲的core就会自己去阻塞队列获取任务执行
- 3:阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
- 4:max满了就会拒绝任务(RejectedExecutionHandler)
- 5:max都执行完成,此时会有很多空闲线程,在指定的时间keepAliveTime以后,会释放(max-core)个线程
2.3具体示例
例如: 一个线程池,core=20,max=50,queue=100,此时有200并发,线程池如何分配
描述: 因为core=20,此时会有20个立刻得到执行,100个会进去队列queue,再开max-core=30个线程来执行任务,剩下的50个就会使用拒绝策略
三:使用Executors创建线程池
使用Executors创建线程池主要是这四种线程池
3.1newFixedThreadPool
ExecutorService executorServicePool= Executors.newFixedThreadPool(10);
创建一个定长的线程池,可控制线程最大并发数,超出的线程会在队列中等待
3.2newCachedThreadPool
ExecutorService executorServicePool= Executors.newCachedThreadPool();
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则创建新线程
3.3newScheduledThreadPool
ExecutorService executorServicePool= Executors.newScheduledThreadPool(10);
创建一个定长线程池,支持定时以及周期性任务执行
3.4newSingleThreadExecutor
ExecutorService executorServicePool= Executors.newSingleThreadExecutor();
创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,任务挨个执行。