线程池状态
ThreadPoolExecutor 使用int的高3位标识线程池状态,低29位标识线程池数量。
线程池的使用
线程池完整构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
参数释义
- corePoolSize 核心线程数
- maximumPoolSize 最大线程数
- 最大线程数 = 核心线程数 + 空闲线程数
- keepAliveTime 空闲线程存活时间
- TimeUnit 空闲线程存活时间单位
- BlockingQueue 任务存放队列
- ThreadFactory 线程工厂,用于生产线程,自定义线程名称
- RejectedExecutionHandler 拒绝策略
线程池工作原理
- 线程池是具备懒惰性的,线程池被实例化时并不会启动任何线程。直到线程池在提交任务时创建线程;先创建核心线程,如果任务超出了核心线程则放入BlockingQueue队列中。如果队列中的任务达到上限才会创建空闲线程。
- 在没有设置配置情况下核心线程不会被销毁
- 核心线程并非固定的某些线程,线程池只保持核心线程数,不保证某一个线程。
线程池 execute 源码
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//判断工作线程数是否小于核心线程数
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))//调用addWorker
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);
}
addWorker 方法
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
......
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask); //封装一个worker,将任务交给worker执行
// woker对象中的线程 t
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //启动worker对象中的线程。启动后会执行worker对象中的run方法
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker构造方法
Worker(Runnable firstTask) {
setState(-1);
// 当前任务
this.firstTask = firstTask;
//获取线程工厂创建一个线程
this.thread = getThreadFactory().newThread(this);
}
Worker对象中的线程strat后执行 Worker对象中 run 方法
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//拿到当前线程任务
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock();
boolean completedAbruptly = true;
try {
//当前task不为空 或者 从队列中获取task不为空
while (task != null || (task = getTask()) != null) {
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
//调用线程中的task执行run方法
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
队列中获取task
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// allowCoreThreadTimeOut默认值为false 不允许核心线程超时被销毁
// wc > corePoolSize 工作线程大于核心线程
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//队列中获取任务
Runnable r = timed ?
//核心线程允许被销毁或者工作线程大于核心线程 调用poll方法
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();//核心线程不允许被销毁调用take方法
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
poll方法 核心线程的等待时间和空闲线程等待时间一致
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//count 队列中的任务数
while (count == 0) {
if (nanos <= 0)
return null;
//这里的notEmpty是一个Condition条件队列
//如果队列中没有任务 调用awaitNanos等待设置的空闲线程等待时间后释放资源
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
核心线程数如果不允许被销毁时调用
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
//永久阻塞
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
模拟线程池案例
自定义线程池
@Slf4j(topic = "marx")
public class CustomerThreadPool {
static AtomicInteger atomicInteger = new AtomicInteger(1);
TaskQueue taskQueue;
static boolean allowCoreThreadTimeout = false;
public CustomerThreadPool(int coreSize, int queueSize) {
this.coreSize = coreSize;
this.queueSize = queueSize;
this.taskQueue = new TaskQueue(queueSize);
}
//所有线程的集合
HashSet<Worker> threadHashSet = new HashSet<>();
//支持的最大核心线程数
int coreSize;
//队列线程数
int queueSize;
public void info(){
log.debug("workThreadSize={}",threadHashSet.size());
}
//向线程池提交一个任务
public void execute(Task task){
//工作中线程数没有达到阈值
if(threadHashSet.size() < coreSize){
log.debug("线程池未满,创建线程分配任务,任务的名称--[{}]",task.getTaskName());
//封装任务worker
Worker worker = new Worker(task,taskQueue);
//任务入队
threadHashSet.add(worker);
//启动任务
worker.start();
}else{
log.debug("线程池已满,放到队列中进行排队,任务的名称--[{}]",task.getTaskName());
taskQueue.offer(task);
}
}
}
线程封装的worker对象
@Slf4j(topic = "marx")
public class Worker implements Runnable{
TaskQueue taskQueue;
//首个任务 实例化worker对象时分配的task
Runnable firstTask;
Thread thread;
public Worker(Runnable firstTask,TaskQueue taskQueue){
this.firstTask = firstTask;
this.taskQueue = taskQueue;
this.thread = new Thread(this,"thread-"+CustomerThreadPool.atomicInteger.incrementAndGet());
}
public Thread getThread() {
return thread;
}
@Override
public void run() {
//执行提交的任务
while (firstTask!=null || (firstTask = taskQueue.take())!=null){
firstTask.run();
firstTask = null;
}
log.debug("没有拿到任务");
}
public Task getTask() throws InterruptedException {
boolean allowCoreThreadTimeout = CustomerThreadPool.allowCoreThreadTimeout;
return allowCoreThreadTimeout?taskQueue.poll(TimeUnit.SECONDS.toNanos(3)):taskQueue.take();
}
public void start(){
log.debug("线程启动---【{}】",thread.getName());
thread.start();
}
}
自定义任务队列
@Slf4j(topic = "marx")
public class TaskQueue {
//这里用reentrantLock是由于实现简单,可以在生产线程和消费线程中精确唤醒,sync则可能会将2者都唤醒
ReentrantLock lock = new ReentrantLock();
//生产者线程 当队列满的时候
Condition full = lock.newCondition();
//消费者线程 当队列为空的时候
Condition empty = lock.newCondition();
Deque<Task> deque = new ArrayDeque<>();
//队列元素上限
private int queueSize;
public TaskQueue(int queueSize) {
this.queueSize = queueSize;
}
/**
* 向任务队列中存放当前任务 需要考虑线程安全问题,因而引入锁
* @param task
*/
public void offer(Task task){
lock.lock();
//临界区代码
try{
//判断队列的界限 当队列已满
while (deque.size() == queueSize){
log.debug("队列已满----阻塞{}",task.getTaskName());
full.await();
}
log.debug("队列未满----可以入队{}",task.getTaskName());
//生产入队
deque.addLast(task);
//唤醒消费
empty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 从队列中取出一个任务
* @return
*/
public Task take(){
lock.lock();
try{
log.debug("取出一个任务");
while (deque.size()==0){
log.debug("队列中没有任务了");
log.debug("永久阻塞---------");
empty.await();
}
//消费出队
Task task = deque.removeFirst();
//唤醒生产
full.signalAll();
return task;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return null;
}
//超时阻塞
public Task poll(long nanos) throws InterruptedException {
lock.lockInterruptibly();
try{
log.debug("取出一个任务");
while (deque.size()==0){
log.debug("队列中没有任务了");
log.debug("超时阻塞--------等待3秒");
if(nanos<=0)
return null;
//当被打断时 awaitNanos 返回剩余时间
nanos = empty.awaitNanos(nanos);
}
//消费出队
Task task = deque.removeFirst();
//唤醒生产
full.signalAll();
return task;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return null;
}
}
自定义任务 主要为了打印任务名
@Slf4j(topic = "marx")
public class Task implements Runnable{
private String taskName;
public Task(String taskName) {
this.taskName = taskName;
}
public String getTaskName() {
return taskName;
}
@Override
public void run() {
log.debug("【{}】任务执行中-----",taskName);
}
}
日常使用线程池
/**
* 最大线程和核心线程为1 等于单线程
* 和自己new线程 || Executors.newFixedThreadPool(1) 区别是什么?
* 1.newSingleThreadExecutor 保证了单个线程
* newFixedThreadPool(1) 可以改变线程池大小,newSingleThreadExecutor不能改变
* 2.如果是创建单线程串行执行,抛出异常会终止。而采用线程池的话,异常线程终止,
* 将会启动新的线程继续执行,但是线程池中的线程数始终保持一条
*/
@Slf4j(topic = "marx")
public class Test {
public static void main(String[] args) {
//newFixedThreadPool(1) 可以通过强转为ThreadPoolExecutor 调用setCorePoolSize 改变线程池大小
ExecutorService executorService = Executors.newFixedThreadPool(1);
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
threadPoolExecutor.setCorePoolSize(3);
//单线程池执行 任务二发生错误后仍然执行任务三
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(()->{
log.debug("执行任务一");
});
executor.execute(()->{
log.debug("执行任务二");
System.err.println(100 / 0);
});
executor.execute(()->{
log.debug("执行任务三");
});
}
}
newFixedThreadPool 采用的是LinkedBlockingQueue队列,队列最大值为Integer.MAX_VALUE
例如:Executors.newFixedThreadPool(100);
每产生一个任务创建一个线程,这个线程执行完任务并不会销毁。假设任务超过设定值100,那么线程池中会保留100核心线程,可用于控制最大并发量场景。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newCachedThreadPool 采用的是同步阻塞队列。适用在单个任务执行时间短任务量大业务场景中效率很高。 由于没有设置核心线程,产生任务后放入到阻塞队列中,创建空闲线程去执行,假设同时创建了5个线程执行,部分线程执行完毕后通过线程复用再到队列中取,可以将资源利用率最大化。
/**
* 1.缓存
* 2.没有核心线程 60s后没有任务 线程池中的线程全部死亡
* 3.空闲线程有 1 << 31 - 1 即 Integer.MAX_VALUE
* 4.同步阻塞队列
* 5.效率高。场景:任务执行时间短,但是任务非常多
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
线程池提交任务
<T> Future<T> submit(Callable<T>task);//接受Feture类型返回值 通过get方法获取,调用get会阻塞
Future<?> submit(Runnable task); //相当于execute
<T>Future<T> submit(Runnable task, T result);//允许传入一个对象用于接收返回结果
阻塞现象演示
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<String> fetureTeak = executorService.submit(() -> {
log.debug("1");
TimeUnit.SECONDS.sleep(1);
return "success";
});
log.debug("start");
log.debug("result[{}]",fetureTeak.get());
log.debug("end");
Executors.newFixedThreadPool(100);
演示结果
execute方法用于提交一个任务
invokeAll 方法可提交多个任务;允许接收多个返回值Feture;允许设置超时时间;会阻塞主线程
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Future<String>> futures = executorService.invokeAll(Arrays.asList(
() -> {
log.debug("1");
return "1";
},
() -> {
log.debug("2");
return "2";
},
() -> {
log.debug("3");
return "3";
},
() -> {
log.debug("4");
return "4";
}
));
log.debug("main start");
for (Future<String> future : futures) {
log.debug( future.get());
}
log.debug("main end");
invokeAny 提交多个任务但不会执行所有任务。一个任务执行结束即返回不再执行其他;会阻塞主线程
ExecutorService executorService = Executors.newFixedThreadPool(10);
Object o = executorService.invokeAny(Arrays.asList(
() -> {
TimeUnit.SECONDS.sleep(3);
log.debug("1");
return "1";
},
() -> {
TimeUnit.SECONDS.sleep(5);
log.debug("2");
return "2";
},
() -> {
TimeUnit.SECONDS.sleep(1);
log.debug("3");
return "3";
},
() -> {
TimeUnit.SECONDS.sleep(6);
log.debug("4");
return "4";
}
));
log.debug("main start");
log.debug("result = [{}]",o);
log.debug("main end");
线程池的停止方法
线程池状态变为SHUTDOWN; 不会接受新任务; 已提交任务继续执行完; 不会阻塞调用线程(main线程)的执行;
void shutdown();
线程池状态变为STOP; 不会接受新任务; interrupt方式打断正在执行的任务,List接收未执行的任务
List<Runnable> shutdownNow();
调用shutdown后;如果再调用 awaitTermination 则表示主线程在等待指定时间单位后解阻塞。 指定时间内线程池执行完则不再等待;如果指定时间内线程池未执行完,则到指定时间后不再等待。
executorService.awaitTermination(3,TimeUnit.Seconds)