1、基础
(1)线程模型的分类
用户线程(ULT)。用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/核心态切换,速度快。内核对ULT无感知,线程阻塞则进程〈包括它的所有线程)阻塞。
内核线程(KLT),系统内核管理线程(KLT),内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞。在多处理器系统上,多线程在多处理器上并行运行。线程的创建、调度和管理由内核完成,效率比ULT要慢,比进程操作快。
(2)java线程与内核线程的关系
jvm运用的是内核级线程模型,java线程与内核线程是一对一的关系
(2)Executor框架
2、线程池的五种状态
(1)五种状态
- Running:能接受新任务以及处理已添加的任务
- Shutdown:不接受新任务,可以处理已经添加的任务
- Stop:不接受新任务,不处理已经添加的任务,并且中断正在处理的任务
- Tidying:所有的任务已经终止, ctl记录的”任务数量”为0 ctl负责记录线程池的运行状态与活动线程数量
- Terminated:线程池彻底终止,则线程池转变为terminated状态
(2)流程
(3)源码(保证线程的安全,将线程池的所有状态保存到一个变量中)
Interger类型的变量的解析:
3、线程池工作原理
(1)五种创建方式
- newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需求可灵活回收空闲线程,若无可回收,则新建线程
- newFixedThreadPool:创建一个定长线程池,可控制线程的最大并发数,超出的线程会在线程池中等待。
- newScheduleThreadPool:创建一个定长线程池,支持定时及周期性任务处理
- newSingleThreadScheduledExecutor:创建一个单线程化的线程池,他只用唯一的工作栈来执行任务,一池一线程
- newSingleThreadExecutor):串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
直接使用Executors创建线程的话,线程的数量没有上限,因此需要手动创建线程池
(2)源码ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,//核心线程池的大小
int maximumPoolSize,//最大线程数量
long keepAliveTime,//线程最长可以空闲多久
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//阻塞队列,在任意时刻不管并发有多高,永远只有一个线程能够进行队列的入队或者出队操作!
队列满,只能进行出队操作,所有入队的操作必须等待,也就是被阻塞
队列空,只能进行入队操作,所有出队的操作必须等待,也就是被阻塞
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
流程:
4、execute方法
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); /* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ int c = ctl.get(); if (workerCountOf(c) < corePoolSize) {//活动线程数小于核心线程数 if (addWorker(command, true))//创建线程实行任务 return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) {//活动线程数大于核心线程数,会加入阻塞队列 int recheck = ctl.get(); if (! isRunning(recheck) && remove(command))//线程不是正常运行的话就从队列中移除 reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false))//最大线程数没有执行成功就会触发拒绝策略 reject(command); }
下面代码的ctl是和下面代码片段的ctl联系的:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
将线程池的所有状态保存到一个Integer类型的变量中去,保证线程的安全。