线程
线程是调度CPU的最小单位,分为KLT与ULT模型。
JVM使用KLT模型,Java与OS保持1:1的映射关系,一个Java线程在OS中也会有一个对应的线程。
线程状态
NEW: 新建
RUNNABLE: 运行
BLOCKED: 阻塞
WAITING: 等待
TIMED_WAITING: 超时等待
TERMINATED: 终结
线程状态切换
线程池
线程属于稀缺资源,如果被无限制创建,不仅会消耗系统资源,还会降低系统的稳定性。
Java中提供线程池(线程缓存池)对线程进行统一分配、调优和监控。
频繁的创建和销毁线程,会大大降低系统的效率。
线程池使用场景
单个任务处理时间比较短;
需要处理的任务数量很大
线程池优势
重用存在的线程,减少线程创建、消亡的开销,提高性能;
提高相应速度。当任务到达直接开始执行,不需要创建;
提高线程的可管理性
线程的实现
- 实现Runnable,重写run()方法;
- 实现Callable,重写call()方法:Callable接收泛型,同时他执行任务后带有返回内容。
Executor框架
只拥有一个用于执行Runnable的execute方法。
- 子接口ExecutorService定义了线程池的具体行为
- execute(Runnable command):履行Runnable命令;
- submit(task):用来提交Callable或者Runnable任务,并返回代表此任务的Future对象;
- shutdown():在完成已提交的任务后封闭办事,不再接管新任务;
- shutdownNow():停止所有正在履行的任务并封闭办事;
- isTerminated():测试是否所有任务都履行完毕了;
- isShutdown():测试该ExecutorService是否已被关闭
重点属性
对线程池的运行状态和线程池中有效线程数量进行控制的一个字段;
包含:线程池的运行状态(runState)和线程池内有效线程的数量(workerCount),它使用Integer:
前三位存储runState,后29位存储workerCount
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
COUNT_BITS = 32-3 = 29
CAPACITY存储workerCount的上限,即29个1,大约是5亿个线程
线程池存在5种状态
- RUNNING
- 线程池处于RUNNING状态是,能够接受新任务,以及对已添加的任务进行处理;
- 线程池的初始化状态,一旦被创建,就处于RUNNING状态,并且线程池中任务数=0
- SHUTDOWN
- 线程池处于SHUTDOWN状态,不接收新任务,但能处理已添加的任务;
- 调用线程池的shutdown(),线程池由RUNNING -> SHUTDOWN
- STOP
- 线程池处在STOP状态时,不再接收新任务,不处理已添加的任务,并且会中断正在处理的任务
- 调用线程池的shutdownNow(),线程池由RUNNING/SHUTDOWN -> STOP
- TIDYING
- 当所有的任务已终止,ctl记录的任务数量为0,线程池会变为TIDYING状态,当线程池变为TIDYING状态时,会执行钩子函数terminated()。用户需重载此函数来实现。
- 线程池处于SHUTDOWN状态,阻塞队列为空并且线程池中执行的任务也为空,就会有SHUTDOWN -> TIDYING。
- 线程池处于STOP状态,线程池中执行的任务为空时,就会由STOP->TIDYING
- TERMINATED
- 线程池彻底中止,就会变为TERMINATED状态
- 线程池处在TIDYING状态时,执行完terminated()之后,就会由TIDYING -> TERMINATED
线程池重要实现
ThreadPoolExecutor – 默认线程池
ScheduledThreadPoolExecutor – 定时线程池
构造函数
corePoolSize – 线程池中核心线程数(CPU密集型:CPU核心数+1, IO密集型:2*CPU核心数+1)
当提交一个任务时,线程池会创建一个新线程执行任务,直到当前线程数=corePoolSize;
如果当前线程数为corePoolSize,继续提交的任务会被保存在阻塞队列中,等待被执行;
maximumPoolSize – 线程池中允许的最大线程数
如果当前任务阻塞队列满了,且继续提交任务,则创建新的线程执行任务,直到当前线程数等于maximumPoolSize
keepAliveTime – 线程池维护线程所允许的空闲时间
当线程池中线程> corePoolSize,如果此时没有任务继续提交,核心线程外的线程不会被销毁,而是会等待,直到等待时间大于keepAliveTime
Unit – keepAliveTime的单位
workQueue – 保存等待被执行的任务的阻塞队列,任务必须实现Runnable接口。
threadFactory – 用来创建线程,默认使用Executors.defaultThreadFactory()来创建线程
handler – 线程池饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略来处理该任务
- AbortPolicy – 直接抛出异常,默认策略
- CallerRunsPolicy – 用调用者所在的线程来执行任务;
- DiscardOldestPolicy – 丢弃阻塞队列中最靠前的任务,并执行当前任务;
- DiscardPolicy – 直接丢弃任务
- 自定义 – 实现RejectExecutionHandler接口
S.D.
源码分析
execute() 提交任务且无返回值,当某一个线程出现异常,不会影响余下线程执行。
- WorkerCount < corePoolSize, 创建并启动一个核心线程来执行新提交的任务;
- workerCount>=corePoolSize且workQueue未满,则将任务加到改阻塞队列中;
- workerCount>=corePoolSize且workerCount
- workerCount>=maximumPoolSize且workQueue已满,则调用拒绝策略进行处理。
addWorker(Runnable firstTask, Boolean core)
在线程池中创建一个新的线程并执行。
firstTask: 用于指定新增的线程执行的第一个任务
core: true【表示在新增线程时会判断当前活动线程是否少于corePoolSize】
false【新增线程前需要判断当前活动线程数是否少于maximumPoolSize】
Worker类
线程池中每个线程被封装为一个Worker对象,ThreadPool维护的就是一组Worker对象。集成AQS,使用AQS来实现独占锁的功能,且不允许重入(与RenntranrLock的区别)
不允许重入理由:任务在调用setCorePoolSize这样的线程池控制方法时不允许重新获取锁,直接阻塞,以免中断正在运行的线程。
public Future> submit() 任务执行完成以后有返回值



