一、创建线程的方式
1.继承Thread类
2.实现Runnable接口
3.实现Callnable接口(有返回值,可抛出异常)
4.线程池
Java提供了Executors可以去创建(规范中不允许使用这种方式创建线程池,这种方式对线程的控制力度比较低)
推荐手动创建线程池
线程池创建方法
线程池的创建方式总共包含以下 7 种(其中 6 种是通过 Executors 创建的,1 种是通过 ThreadPoolExecutor 创建的):
Executors.newFixedThreadPool():创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
Executors.newCachedThreadPool():创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收多余的线程,若线程数不够,则新建线程;
Executors.newSingleThreadExecutor():创建单个线程数的线程池,它可以保证先进先出的执行顺序;
Executors.newScheduledThreadPool():创建一个可以执行延迟任务的线程池;
Executors.newSingleThreadScheduledExecutor():创建一个单线程的可以执行延迟任务的线程池;
Executors.newWorkStealingPool():创建一个抢占式执行的线程池(任务执行顺序不确定)JDK 1.8 添加
ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置
单线程池的意义: 虽然 newSingleThreadExecutor 和 newSingleThreadScheduledExecutor 是单线程池,但提供了工作队列,生命周期管理,工作线程维护等功能。
二、线程池的七个参数
public ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 最大空闲时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 阻塞队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
三、线程池流程
四、线程池属性标识
//是一个int类型的数值,表达了两个意思,1:声明当前线程池的状态 2:声明线程池中的线程数
//高3位:线程池状态 第29位是:线程池中的个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 32-3 = 29
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1; //0001111111111111111111最大容量
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS; //111 代表线程池位RUNNING状态,正常接收任务
private static final int SHUTDOWN = 0 << COUNT_BITS;
//000 代表线程池位SHUTDOWN状态,不接收新任务,但是内部还会处理阻塞队列中的任务,正在进行的任务也正常处理
private static final int STOP = 1 << COUNT_BITS;
//001 代表线程池位STOP状态,不接收新人券,也不去处理阻塞队列中的任务,同时会中断正在执行的任务
private static final int TIDYING = 2 << COUNT_BITS;
//010 代表线程池位TIDYING状态,过渡的状态,代表当前的线程池即将结束
private static final int TERMINATED = 3 << COUNT_BITS;
//011 代表线程池位TERMINATED,要执行terminated(),线程池结束
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~COUNT_MASK; } //得到线程池的状态
private static int workerCountOf(int c) { return c & COUNT_MASK; } //得到当前线程池的线程数量(正在工作的线程)
private static int ctlOf(int rs, int wc) { return rs | wc; }
4.2线程池状态变化
五、线程池的Execute方法执行
从execute方法开始
public void execute(Runnable command) {
//健壮性判断
if (command == null)
throw new NullPointerException();
//拿到32位的int
int c = ctl.get();
//获取工作线程数 <核心线程数
if (workerCountOf(c) < corePoolSize) {
//进到if,代表可以创建核心线程
//A,B
if (addWorker(command, true))
return;
//创建核心线程数失败,重新获取ctl
c = ctl.get();
}
//判断线程池是不是Running,将任务添加到阻塞队列中
if (isRunning(c) && workQueue.offer(command)) {
//再次过去ctl
int recheck = ctl.get();
//再次判断是否是RUNNING,如果不是,移除任务
if (! isRunning(recheck) && remove(command))
reject(command); //拒绝策略
//如果线程池处在RUNNING状态,但是工作线程为0
else if (workerCountOf(recheck) == 0)
//阻塞队列有任务,但是没有工作线程,添加一个任务为空的工作线程处理阻塞队列中的任务
addWorker(null, false);
}
// 创建非核心线程处理任务
else if (!addWorker(command, false))
reject(command); //拒绝策略
}
通过上述源码,掌握了线程池操作的执行流程,再次查看addWorker方法内部做了什么处理
private boolean addWorker(Runnable firstTask, boolean core) {
retry: //标记for循环,内部for跳出外层for循环
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
//Worker就是工作线程
Worker w = null;
try {
//创建Worker,传入任务
w = new Worker(firstTask);
//从Worker中获取线程t
final Thread t = w.thread;
if (t != null) {
//获取线程池的全局锁,避免添加任务时别的线程干掉了线程池,干掉线程需要先获取这个锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock(); //加锁
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
//工作线程放在hashset中
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //启动工作线程
workerStarted = true; //启动工作线程成功
}
}
} finally {
if (! workerStarted) //如果启动工作线程失败
addWorkerFailed(w);
}
return workerStarted;
}