Java线程池
概述
在Java中为我们提供了线程池来管理我们所创建的线程。
线程池的优势:
1 . 降低系统资源消耗,通过复用已存在的线程,降低线程创建和销毁造成的消耗;
2 . 提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行;
3 . 方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或出现OOM等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提高资源使用效率;
4 . 线程池提供了定时、定期以及可控线程数等功能,使用方便简单;
ThreadPoolExecutor
ThreadPoolExecutor构造方法中的参数如下:
1 . corePoolSize:线程池中的核心线程数;
2 . maximumPoolSize:线程池中所能容纳的最大线程数;
3 . keepAliveTime:非核心线程闲置时的超时时长;
4 . unit:用于指定keepAliveTime参数的时间单位;
5 . workQueue:线程池中保存等待执行的任务的阻塞队列;我们还可以通过实现BlockingQueue接口来自定义我们所需要的阻塞队列;
阻塞队列 | 说明 |
---|---|
ArrayBlockingQueue | 基于数组实现的有界的阻塞队列,该队列按照先进先出的原则对队列中的元素进行排序 |
LinkedBlockingQueue | 基于链表实现的阻塞队列,该队列按照先进先出的原则对队列中的元素进行排序 |
SyschronousQueue | 内部没有任何容量的阻塞队列;在它内部没有任何的缓存空间;对于SyschronousQueue中的数据元素只有当我们试着取走的时候才可能存在 |
PriorityBlockingQueue | 具有优先级的无限阻塞队列 |
6 . threadFactory:线程工厂,为线程池提供新线程的创建;
7 . handler:是RejectedExecutionHandler对象;
线程池执行流程
1 . 如果在线程池中的线程数量没有达到核心的线程数量,这时候就会启动一个核心线程来执行任务;
2 . 如果线程池中的线程数量已经超过核心线程数,这时候任务就会被插入到任务队列中排队等待执行;
3 . 由于任务队列已满,无法将任务插入到任务队列中。这时候如果线程池中的线程数量没有达到线程池所设定的最大值,那么这时候就会立即启动一个非核心线程来执行任务;
4 . 如果线程池中的数量达到了所规定的最大值,那么就会拒绝执行此任务,这时候就会调用RejectedExecutionHandler中的rejectedExecution()方法来通知调用者;
四种线程池类
Java中四种具有不同功能常见的线程池。它们都是直接或间接配置ThreadPoolExecutor来实现它们各自的功能。这四种线程池分别是newFixedThreadPool、newCachedThreadPool、newScheduledThreadPool、newSingleThreadExecutor。这四个线程池可以通过Executors类来获取。
newFixedThreadPool
newCachedThreadPool
newScheduledThreadPool
newSingleThreadExecutor
线程池的使用技巧
需要针对具体的情况来具体处理,不同的任务类别应该采用不同规模的线程池,任务类别可以划分为CPU密集型任务、IO密集型任务、混合型任务;(N代表CPU个数)
任务类别 | 说明 |
---|---|
CPU密集型任务 | 线程池中线程个数应尽量少,如配置N + 1个线程的线程池 |
IO密集型任务 | 由于IO操作速度远低于CPU速度,那么在运行这类任务时,CPU绝大多数时间处于空闲状态,那么线程池可以配置尽量多些的线程,以提高CPU利用率,如2 * N |
混合型任务 | 可以拆分为CPU密集型任务和IO密集型任务,当这两类任务执行时间相差无几时,通过拆分再执行的吞吐率高于串行执行的吞吐率,但若这两类任务执行时间又数据级的差距,那么没有拆分的意义 |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
--------------------last line for now-------------------