java线程池框架源代码分析
相关类Executor,Executors。AbstractExecutorService。ExecutorService
Executor:整个线程池运行者框架的顶层接口。
定义了一个execute方法。整个线程运行者框架的核心方法。
public interface Executor {
void execute(Runnable command);
}
ExecutorService:这是一个接口它继承自Executor,定义了shutdown。shutdownNow,awaitTermination,submit。invokeAll等方法。
AbstractExecutorService:实现了ExecutorService接口中的submit,invokeAll的方法。
public Future<?
> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
在这里。全部submit方法提交的任务终于还是调用了execute方法。execute是接口Executor中定义的方法,AbstractExecutorService没有实现它,
须要子类去实现这种方法。ThreadPoolExecutor继承了AbstractExecutorService,它实现了execute方法。ScheduledThreadPoolExecutor继承自
ThreadPoolExecutor,并覆盖了ThreadPoolExecutor的execute方法。这种方法是线程运行框者架的核心逻辑,不同的线程池运行者有不同的实现逻辑。
AbstractExecutorService的功能较为简单。实现了不同參数的submit。invokeAll方法。
ThreadPoolExecutor线程池运行者:它有一个核心的成员变量:
private final HashSet<Worker> workers = new HashSet<Worker>();
workers能够看做是ThreadPoolExecutor中用于执行任务的线程池。
worker是一个封装了一个Thread对象并实现了Runnable接口的类。
封装Thread非常easy理解,由于它要利用Thread去执行execute方法提交过来的runnable任务。
可是为什么会继承runnable接口呢?
以下是剔除了部分代码的Worker源代码:
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
final Thread thread; Runnable firstTask; Worker(Runnable firstTask) {
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
} public void run() {
runWorker(this);
} }
Worker是ThreadPoolExecutor的一个内部类,Worker本身实现了Runnable接口,并封装了一个Thread对象,最后在构造方法中获取了一个Runnable对象,这个对象就是ThreadPoolExecutor通过execute提交过来的目标任务。
跟踪runWorker(this)方法:
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock();
boolean completedAbruptly = true;
try {
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();//在这里直接调用了目标任务的run方法,并没有将它传给Thread对象。
} 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);
}
}
回过头来在看看Worker的构造方法:
Worker(Runnable firstTask) {
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
它将自己传给了自己的成员变量thread。
目标任务被运行的步骤可能就是:Worker的成员变量thread启动后调用worker的run方法。worker的run方法中将自己传给runWorker,runWorker在调用目标运行对象的run方法。
那么thread是何时被运行的呢?
以下看看ThreadPoolExecutor中的一个其它方法:
private boolean addWorker(Runnable firstTask, boolean core) {
......
try {
final ReentrantLock mainLock = this.mainLock;
w = new Worker(firstTask);
final Thread t = w.thread;//这里初始化一个Worker对象w。在将w的成员变量thread付给t
if (t != null) {
mainLock.lock();
try {
int c = ctl.get();
int rs = runStateOf(c);
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();//在这里调用t的start方法。
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
这里为什么会设计的这么绕,我想主要是Worker不仅封装了一个thread,并且对目标任务进行了封装。在执行封装过后的目标任务前,addWorker能够做一些相关操作。
这里只介绍了ThreadPoolExecutor的线程池。那么这个线程池是怎样被维护的。以下介绍几个关键的參数。
private volatile int corePoolSize;
private volatile int maximumPoolSize;
private final BlockingQueue<Runnable> workQueue;
这三个是ThreadPoolExecutor的成员变量,当中workQueue跟县城池没有关系。
workQueue是一个线程安全的堵塞队列。
corePoolSize是线程池的核心大小。maximumPoolSize是线程池的最大大小。
当提交新任务时,假设ThreadPoolExecutor中有线程在执行。而且线程的数量小于corePoolSize,那么就会有新的线程被创建。
假设当前执行的线程数大于corePoolSize,就会放到缓存队列workQueue中。假设缓冲队列也满了。就继续创建线程,直到线程的数量达到maximumPoolSize
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//推断假设当前执行的线程数小于 corePoolSize,加入新的线程(addWorker会加入一个新的线程。上面有介绍),方法直接返回。
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//假设当前的执行的线程数大于或等于corePoolSize则新的任务会放到缓存队列中。
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);
}
还有些其它的參数:
private volatile ThreadFactory threadFactory //线程的工厂函数。 private volatile RejectedExecutionHandler handler;//任务拒绝的处理类。
private volatile long keepAliveTime;//任务等待的是将。
ThreadPoolExecutor有几个构造方法来初始化这些參数。Executors类将这些參数简化了来获得一个ExecutorService的引用。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
这四个方法中前两个的核心线程数和最大线程数同样,全部可执行的线程数是固定的,<=nThreads。
当任务数大于nThreads时,就是放入缓冲队列中。 后两个方法中,线程数是无边界的,核心线程数是0,最大线程数是整型的最大值,然后假设有线程60秒内没有任务执行的话就销毁。每次有新的任务来,都会创建新的线程或使用曾经创建的线程(60秒内没有任务执行的线程)。
你可能有疑问。既然核心线程数是0,那么全部的任务不是都放到队里里了吗?那么如今就来看看SynchronousQueue这个队里,能够看看这里的介绍http://wsmajunfeng.iteye.com/blog/1629352/。
回过头来看看任务提交方法的源代码:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {//这里是在往队列里方任务,假设不成功就会加入Worker(封装了线程对象)
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);
}
上面链接里的博客提到:offer()往queue里放一个element后马上返回,假设碰巧这个element被还有一个thread取走了,offer方法返回true。觉得offer成功;否则返回false。
试想一下,第一次提交任务的时候,核心线程数为0,此时没有线程所以没有线程从workQueue中取东西,所以这里的workQueue.offer(command)会返回false,那么就会通过addWorker(command, false)创建一个新的线程。
java线程池框架源代码分析的更多相关文章
- Java 线程池框架核心代码分析--转
原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...
- Java 线程池框架核心代码分析
前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...
- Java线程池原理及分析
线程池是很常用的并发框架,几乎所有需要异步和并发处理任务的程序都可用到线程池. 使用线程池的好处如下: 降低资源消耗:可重复利用已创建的线程池,降低创建和销毁带来的消耗: 提高响应速度:任务到达时,可 ...
- Java线程池使用和分析(一)
线程池是可以控制线程创建.释放,并通过某种策略尝试复用线程去执行任务的一种管理框架,从而实现线程资源与任务之间的一种平衡. 以下分析基于 JDK1.7 以下是本文的目录大纲: 一.线程池架构 二.Th ...
- Java线程池使用和分析(二) - execute()原理
相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...
- Java 线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- 【图灵学院10】高并发之java线程池源码分析
1. 提纲 1)线程池的模块结构 2)示例&原理解析 2. 问题 1)线程池包含哪些东西 2)线程池的运作原理 3)调度线程池的运作原理 4)线程池怎么实现FixRate,FixDelay,他 ...
- Java 线程池(ThreadPoolExecutor)原理分析与实际运用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:< ...
随机推荐
- ImageButton-设置background跟src
xml中添加ImageButton的background跟src <ImageButton android:id="@+id/tv3" android:layout_widt ...
- Android Studio - no debuggable applications 的解决的方法
之前logcat总是无法显示调试应用的信息 曾经我都是卸载重装.后来发如今StackOverflow有一个哥们说的非常对.一次就成功. 原话是这么说的: You also should have To ...
- POJ 2376 Cleaning Shifts 区间覆盖问题
http://poj.org/problem?id=2376 题目大意: 给你一些区间的起点和终点,让你用最小的区间覆盖一个大的区间. 思路: 贪心,按区间的起点找满足条件的并且终点尽量大的. 一开始 ...
- JNI之——Can't load IA 32-bit .dll on a AMD 64-bit platform错误的解决
转载自:http://blog.csdn.net/l1028386804/article/details/46605003 在JNI开发中,Java程序需要调用操作系统动态链接库时,报错信息:Can' ...
- 使用stringstream进行类型转换与字符串分割
C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性.类型安全和可扩展性. 如果你已习惯了<stdio.h>风格的转 ...
- uva 10710 - Chinese Shuffle(完美洗牌)
option=com_onlinejudge&Itemid=8&category=474&page=show_problem&problem=1651"> ...
- HDU 5237 Base64
Base64 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Sub ...
- Android java.lang.IllegalArgumentException: Object returned from onCreateLoader must not be a non-static inn
AsyncTaskLoader: http://developer.Android.com/intl/zh-CN/reference/android/content/AsyncTaskLoader.h ...
- LA 3602 - DNA Consensus String 枚举
原题地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- [Debug] Use Snippets to Store Behaviors in Chrome DevTools
Using the Snippets tab in the source devtool you can define and run arbitrary pieces of code in your ...