线程池

线程池处理流程

  • 核心线程池:创建新线程执行任务,需要获取全局锁
  • 队列:将新来的任务加入队列
  • 线程池:大于corePoolSize,并且队列已满,小于maxPoolSize,创建新的worker执行任务
  • 线程池已满(达到max)处理策略:大于线程最大处理能力,大于maxPoolSize,选择拒绝策略

尽可能避免获取全局锁,corePoolSize就是这个作用,线程池开始处理任务,预热达到corePoolSize之后,将新来的任务放入队列

execute

public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// ctl是一个AtomInteger,低29为表示线程数workerCount,高3位表示线程池运行状态runState
int c = ctl.get();
// 当前前程数小于核心线程数corePoolSize,新建核心线程处理任务
if (workerCountOf(c) < corePoolSize) {
// 第二个参数为true表示新建的核心线程
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);
}
// 如果放入队列失败(队列已满),则新建线程处理任务,第二个参数为false表示新建的是非核心线程
else if (!addWorker(command, false))
// 如果已经超过最大线程数,采取相应的拒绝策略
reject(command);
} // 第一个参数是需要运行的任务
// 第二个参数是为了区分核心线程和非核心线程,用来确定线程池的边界是corePoolSize还是maxPoolSize
// 本方法的作用就是新建一个worker线程并启动
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false; // 循环确保CAS操作成功
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 成功增加workerCount则跳出外层循环,开始新建线程
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
} boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
// 新建worker线程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 可重入锁,加锁
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
int rs = runStateOf(c); if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将新建的线程放入线程池中,其实就是一个HashSet
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 如果成功加入线程池则启动线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
// 返回线程是否启动成功
return workerStarted;
}

创建线程

// 在addWorker中新建线程
w = new Worker(firstTask); // Worker的构造方法
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
} // 这里以ThreadFactory的一个实现DefaultThreadFactory为例
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
// 新建一个线程组,线程池中所有线程都由线程组统一管理
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
} // 新建线程
public Thread newThread(Runnable r) {
// 新建的线程属于线程组group,r为Worker对象
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}

线程池中的worker线程执行任务

// 在addWorker中会启动worker线程
if (workerAdded) {
t.start();
workerStarted = true;
} // 线程启动之后会执行worker的run方法
// 调用外部类ThreadPoolExecutor的runWorker方法
public void run() {
runWorker(this);
} // runWorker,worker线程循环执行来自workerQueue的任务(除firstTask外)
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
// 新建线程以后会执行第一个任务,新建Worker线程的时候传入的任务
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// worker不断从workerQueue中getTask执行,
// 如果没有获取任务并且返回,则while循环结束,worker线程结束
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 调用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);
}
} // 从workerQueue中获取task,workerQueue是BlockingQueue
// 如果返回null,则会导致worker线程结束
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out? retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
} // 决定没有任务的时候线程是结束还是等待任务
boolean timed; // Are workers subject to culling? for (;;) {
int wc = workerCountOf(c);
// 当allowCoreThreadTimeOut为true或者当前线程数大于核心线程数的时候timed为true
// allowCoreThreadTimeOut为true:允许线程没有任务的时候超时退出
// wc > corePoolSize:表示当前线程数足够,可以结束,以维持核心线程数
timed = allowCoreThreadTimeOut || wc > corePoolSize; if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
if (compareAndDecrementWorkerCount(c))
return null;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
} try {
// workQueue.poll:等待keepAliveTime纳秒之后,如果获取到则返回任务,否则返回null
// workQueue.take:如果没有获取到任务,线程会一直阻塞,直到被唤醒(什么时候会被唤醒:新加入task的时候,poll后队列中元素数依然大于1个,队列中元素数等于capacity),所以take如果返回的话一定是非空的
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}

线程池满之后的拒绝策略

CallerRunsPolicy

直接在调用线程池所在的线程运行(调用)

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
// 直接调用run方法
r.run();
}
}

AbortPolicy

throw Exception

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}

DiscardPolicy

直接丢弃,不做任何操作

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}

DiscardOldestPolicy

丢弃最老任务的策略

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
// 移除第一个任务,也就是最老(最先进来的)任务
e.getQueue().poll();
// 执行当前传入的任务
e.execute(r);
}
}

问题

线程池的“池”体现在哪里

  • 平时使用线程都是直接继承Thread然后,调用start,然后Thread.start通过native调用创建新的线程并回调自己定义的run方法,所以每次调用一次run方法都需要新建一个线程
  • 线程池就是,启动一个线程(Worker)调用完一个run(直接调用,不再通过Thread.start)方法之后并不会立即退出,会运行在队列中等待的其他run方法(这里是循环,从队列中获取),如果队列中没有需要继续运行的线程则当前worker线程会休眠

Java 线程 — ThreadPoolExecutor的更多相关文章

  1. Java线程--ThreadPoolExecutor使用

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11871132.html Java线程--ThreadPoolExecutor使用 public ...

  2. Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  3. java线程池技术(二): 核心ThreadPoolExecutor介绍

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...

  4. Java 线程池(ThreadPoolExecutor)原理分析与使用

    在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...

  5. Java 线程池(ThreadPoolExecutor)原理解析

    在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...

  6. Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  7. Java线程池ThreadPoolExecutor使用和分析(一)

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  8. Java线程池(ThreadPoolExecutor)原理分析与使用

    在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...

  9. 转:JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue

    从Java5开始,Java提供了自己的线程池.每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池.以下是我的学习过程. 首先是构 ...

随机推荐

  1. 使用echarts开发电子屏数据展示页面

    背景 之前的项目因为要顾及体量问题,选用了highchart,没用上echarts:这次因为是本地部署电子屏幕的展示页,不需要考虑体量大小,直接用上了echarts:用起来觉得非常不错,特别是地图上非 ...

  2. [基础技能] 安全技术——哈希算法密码破解之彩虹表(Rainbow Table)学习

    1.基础知识 刚刚学习过数字签名的相关知识,以及数字签名的伪造技术,而伪造数字签名归根结底就是密码破解的一个过程,然而直接破解的速度是非常缓慢的,所以有人想出一种办法,直接建立出一个数据文件,里面事先 ...

  3. Python 进程间通信

    from multiprocessing import Process,Queue import os,time,random def write(q): print('Process to writ ...

  4. 图解修改mysql的默认数据库存放目录

    按照下图三步完成:

  5. (RMQ版)LCA注意要点

    inline int lca(int x,int y){ if(x>y) swap(x,y); ]][x]]<h[rmq[log[y-x+]][y-near[y-x+]+]])? rmq[ ...

  6. mysql中生产表格多列统计问题

    for Example: select date_format(date,'%Y-%m-%d') as day, count(case when xinghao='a' then 1 end) as  ...

  7. 二分图&网络流&最小割等问题的总结

    二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...

  8. ubuntu14.04 安装 hadoop2.4.0

    转载:ubuntu搭建hadoop-Ver2.6.0完全分布式环境笔记 自己在搭建hadoop平台时,碰到一些困难,按照该博文解决了问题,转载一下,作为记录. 2 先决条件 确保在你集群中的每个节点上 ...

  9. CSS3动画快速实现

    在工作或者平时做demo中,经常会遇到做一些简单的动画.初级前端同学可能就会有些棘手了. 在这里我发现了一个网上笔记实用且简单易上手的动画库.与大家共享一下: 更多请查看:http://anicoll ...

  10. java关于ArrayList中toArray方法的使用

    先来看下面这段程序 Collection collect= new ArrayList();   collect.add("小黑");   collect.add("小白 ...