前言
Java的线程既是工作单元,也是执行机制。从JDK 5开始,把工作单元与执行机制分离开来。工作单元包括Runnable和Callable,而执行机制由Executor框架提供。
线程池
Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。在开发过程中,合理地使用线程池能够带来3个好处。
- 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
线程池实现原理
当提交一个新任务到线程池时,线程池的处理流程如下。
1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
线程数量要点:
如果运行线程的数量少于核心线程数量,则创建新的线程处理请求
如果运行线程的数量大于核心线程数量,小于最大线程数量,则当队列满的时候才创建新的线程
如果核心线程数量等于最大线程数量,那么将创建固定大小的连接池
如果设置了最大线程数量为无穷,那么允许线程池适合任意的并发数量
线程空闲时间要点:
当前线程数大于核心线程数,如果空闲时间已经超过了,那该线程会销毁。
拒绝任务策略:
直接抛出异常
使用调用者的线程来处理
直接丢掉这个任务
丢掉最老的任务
Executor框架
两级调度模型
在上层,Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。
应用程序通过Executor框架控制上层的调度;而下层的调度由操作系统内核控制,下层的调度不受应用程序的控制。
Executor框架的结构
Executor框架主要由3大部分组成如下。
1.任务。包括被执行任务需要实现的接口:Runnable接口或Callable接口。
2.任务的执行。包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。Executor框架有两个关键类实现了ExecutorService接口(ThreadPoolExecutor和ScheduledThreadPoolExecutor)。
3.异步计算的结果。包括接口Future和实现Future接口的FutureTask类。
Executor框架的成员
本节将介绍Executor框架的主要成员: ThreadPoolExecutor、ScheduledThreadPoolExecutor,Future接口、Runnable接口、Callable接口和Executors。
(1)ThreadPoolExecutor
ThreadPoolExecutor通常使用工厂类Executors来创建。Executors可以创建3种类型的ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool和CachedThreadPool。
1)FixedThreadPool。下面是Executors提供的,创建使用固定线程数的FixedThreadPool的API。FixedThreadPool适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。
2)SingleThreadExecutor。下面是Executors提供的,创建使用单个线程的SingleThreadExecutor的API。SingleThreadExecutor适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
3)CachedThreadPool。下面是Executors提供的,创建一个会根据需要创建新线程的CachedThreadPool的API。CachedThreadPool是大小无界的线程池,适用于执行很多的短期异步务的小程序,或者是负载较轻的服务器。
(2)ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor通常使用工厂类Executors来创建。Executors可以创建2种类型的ScheduledThreadPoolExecutor,如下。
1)ScheduledThreadPoolExecutor。包含若干个线程的ScheduledThreadPoolExecutor。
ScheduledThreadPoolExecutor适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。
2)SingleThreadScheduledExecutor。只包含一个线程的ScheduledThreadPoolExecutor。
SingleThreadScheduledExecutor适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景。
(3)Future接口
Future接口和实现Future接口的FutureTask类用来表示异步计算的结果。当我们把Runnable接口或Callable接口的实现类提交(submit)给ThreadPoolExecutor或ScheduledThreadPoolExecutor时,ThreadPoolExecutor或ScheduledThreadPoolExecutor会向我们返回一个FutureTask对象。
(4)Runnable接口和Callable接口
Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutorScheduledThreadPoolExecutor执行。它们之间的区别是Runnable不会返回果,而Callable可以返回结果。