1.使用Executors执行器创建线程池
- newFixedThreadPool:固定个数线程池
- 特点:核心线程数等于最大线程数;空闲时间为0;使用链表阻塞队列(无界队列)LinkedBlockingQueue
- newSingleThreadExecutor:可执行线程数为1
- 特点:核心线程数等于最大线程数=1;空闲时间为0;使用链表阻塞队列(无界队列)LinkedBlockingQueue
- newCachedThreadPool:缓冲线程池
- 特点:核心线程数为0;最大线程数为Integer.MAX_VALUE;空闲时间为60s;阻塞队列为SynchronousQueue
- newScheduledThreadPool:定时线程池
- 特点:指定核心线程数;最大线程数为Integer.MAX_VALUE;空闲时间为0;阻塞队列为DelayedWorkQueue
- newWorkStealingPool:分而治之线程池
- 特点:底层使用的是ForkJoinPool线程池;相当于对ForkJoinPool的封装,可以更好的调用;每一个线程对应一个阻塞队列
- 总结:为什么高并发任务不推荐使用Executors提供的默认线程池?
- newFixedThreadPool和newSingleThreadExecutor使用的是无界队列,任务量过多时,队列占用内存过大,容易oom
- newCachedThreadPool和newScheduledThreadPool的最大线程数为Integer.MAX_VALUE,任务过多时可能生成过多的线程,导致oom,同时线程数过多可能导致CPU频繁上下文切换,影响CPU性能
2.线程池中线程执行流程简易说明
线程池中的线程执行任务的任务不是我们通过excuse或者submit提交的任务,而是在threadpollservice里面定义了一个内部类Worker,该内部类实现了runnable接口;线程真正执行的任务就是该内部类run方法,然后再该内部类的run方法里面循环队列执行提交的任务;当满足线程过期时间之后回跳出循环从而导致线程run方法执行完毕,线程回收。
3.线程池任务执行流程
- 当前线程池线程数小于核心线程数,则创建线程执行任务。
- 当前线程池线程数大于核心线程数,判断阻塞队列是否已满,未满则将任务放入阻塞队列。
- 阻塞队列已满,则判断当前线程池线程数是否小于最大线程数,小于则创建线程执行任务。
- 当前线程池线程数等于最大线程数,并且阻塞队列已满,则执行拒绝策略。
4.线程池常见拒绝策略
- AbortPolicy:丢弃任务,抛出异常
- CallerRunsPolicy:调用者执行任务,主线程执行
- DiscardPolicy:丢弃任务,不抛出异常
- DiscardOldestPolicy:丢弃队列里最老的任务,新任务进入队列
- 实现RejectedExecutionHandler 接口自定义拒绝策略
5.自定义线程池时,7个常用参数
- corePoolSize:核心线程数
- maximumPoolSize:线程池最大线程数
- keepAliveTime:线程闲置超时时间,超过该时间的限制线程会被回收,核心线程除外
- unit:线程闲置超时时间单位
- workQueue:任务队列
- threadFactory:线程工厂,用于创建线程
- rejectedExecutionHandler:拒绝策略