文章目录
一、并发框架
Executors(阿里巴巴开发手册不推荐使用队列无界的线程池)
不推荐使用的原因是因为有部分队列是无界的意思是在核心线程处理不过来的情况下全部丢到队列中等待执行,这样就会堆积很多的任务导致OOM(无界相当于是存储Int最大值个任务,这种情况下20亿个任务等待到不了最大值系统资源就会被消耗一空)
- Executors框架其内部采用了线程池机制,他在java.util.cocurrent包下,通过该框架来控制线程的启动、执行、关闭,可以简化并发编程。
- Executor接口中定义了方法execute(Runable able)接口,该方法接受一个Runable实例,他来执行一个任务,任务即实现一个Runable接口的类。
- executor提供了工厂的方法来创建线程池,返回的线程池都实现了ExecutorService接口。
类解释
- Executor
一个接口,其定义了一个接收Runnable对象的方法executor,Executor.execute(Runnalbe)。Executor在执行时使用内部的线程池完成操作。 - ExecutorService
是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法。 - Future
Future代表的是异步执行的结果,意思是当异步执行结束之后,返回的结果将会保存在Future中。 - AbstractExecutorService
ExecutorService执行方法的默认实现 - ScheduledExecutorService
一个可定时调度任务的接口 - ScheduledThreadPoolExecutor
ScheduledExecutorService的实现,一个可定时调度任务的线程池 - ThreadPoolExecutor
线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:
二、线程池的参数属性
2.1ThreadPoolExecutor线程池的核心属性
-
int corePoolSize
核心线程数 -
int maximumPoolSize
线程池最大线程数 -
long keepAliveTime
线程保持活跃的时间,默认情况下,该参数只针对超过核心线程数( corePoolSize ) 的线程,可通过将 allowCoreThreadTimeOut 设置为 true,则核心线程数也会因为空闲而被关闭。
-
TimeUnit unit
keepAliveTime 的时间单位
-
BlockingQueue< Runnable > workQueue
任务挤压队列
-
ThreadFactory threadFactory
线程创建工厂类
-
RejectedExecutionHandler handler
拒绝策略
2.2队列类型
- ArrayBlockingQueue
是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
- LinkedBlockingQueue
一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
- SynchronousQueue
一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool(5)使用了这个队列。
- PriorityBlockingQueue(不推荐使用)
一个具有优先级的无限阻塞队列。
2.3拒绝策略
-
AbortPolicy
拒绝,直接抛出 RejectedExecutionException,默认值。
-
CallerRunsPolicy
由调用线程直接运行任务的 run 方法,即异步转同步。
-
DiscardOldestPolicy
丢弃任务队列中最先进入的任务。
-
DiscardPolicy
拒绝了,就不执行,“当没事人事”样。
注意:拒绝策略触发的条件:线程池使用的是有界任务队列时,才有可能被触发,当队列已满,并且线程池创建的线程已经达到了最大允许的线程池时。
默认情况下,通常使用 AbortPolicy 即可。
2.4ThreadFactory
简单来说就是用来创建线程的,其中也只是有一个newthread方法。
一些常用的作用
- 给线程命名,查看创建线程数
- 给线程设置是否是后台运行
- 设置线程优先级
三、创建线程的过程
- 提交任务时会创建新的线程添加进入线程池中,如果线程池中的线程数量未达到核心线程数量则直接添加线程,如果超过了则将此任务添加进入任务队列中等待线程消费。
- 当队列为有界队列则超过队列大小限制就会创建新的线程直到到达线程池最大线程数量,如果线程池已满则会启用任务拒绝策略。
- 如果线程池处理不过来任务有四种策略应对这些处理不了的任务,通常使用AbortPolicy直接拒绝该任务
四、线程池种类
4.1固定线程池Executors.newFixedThreadPool
详细介绍
创建固定线程数的线程池,使用的是LinkedBlockingQueue无界队列,线程池中实际线程数永远不会变化
应用场景
适用于可以预测线程数量的业务中,或者服务器负载较重,对线程数有严格限制的场景
实现实现
4.2单一线程池Executors.newSingleThreadExecutor
详细介绍
创建只有一个线程的线程池,使用的是LinkedBlockingQueue无界队列,线程池中实际线程数只有一个
应用场景
适用于需要保证顺序执行各个任务,并且在任意时间点,不会同时有多个线程的场景
4.3缓存线程池Executors.newCachedThreadPool
详细介绍
创建可供缓存的线程池,该线程池中的线程空闲时间超过60s会自动销毁,使用的是SynchronousQueue特殊无界队列
应用场景
适用于创建一个可无限扩大的线程池,服务器负载压力较轻,执行时间较短,任务多的场景
4.4调度线程池Executors.newScheduledThreadPool
详细介绍
创建可供调度使用的线程池(可延时启动,定时启动),使用的是DelayWorkQueue无界延时队列
应用场景
适用于需要多个后台线程执行周期任务的场景
4.5多任务队列线程池Executors.newWorkStealingPool
详细介绍
jdk1.8提供的线程池,底层使用的是ForkJoinPool实现,创建一个拥有多个任务队列的线程池,可以减少连接数,创建当前可用cpu核数的线程来并行执行任务
应用场景
适用于大耗时,可并行执行的场景
4.6自定义ThreadPoolExecutor
详细介绍
上述讲的Executors创建的线程池底层都是由ThreadPoolExecutor实现的只不过参数不同让上述的各种线程池有了不同的个性和功能。
应用场景
对线程管理比较严格,需要自己动态的调整线程池大小的情况。
参考资料
docs.oracle.com/javase/7/do…
blog.csdn.net/qq_35029061…
中间件兴趣圈作者丁威
my.oschina.net/u/3847203/b…
blog.csdn.net/weixin_3403…
blog.csdn.net/u012253957/…
www.cnblogs.com/yangdagaoge…