ThreadPoolExecutor阅读笔记
文章目录
一、简介
JDK常用的线程池,里面有一个内部Worker类继承了AQS实现了Runnable
二、继承关系图
三、存储结构
- 核心线程
- 最大线程(超过核心线程的加入队列)
- 超时时间
- 线程工厂
- 拒绝策略
四、源码分析
内部类
Worker
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
// 真正工作的线程
final Thread thread;
/** Initial task to run. Possibly null. */
// 第一个任务,从个构造方法传进来
Runnable firstTask;
/** Per-thread task counter */
// 完成任务数
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
// 构造方法
Worker(Runnable firstTask) {
// 设置为等待唤醒状态
setState(-1); // inhibit interrupts until runWorker
// 第一个任务
this.firstTask = firstTask;
// 使用线程工厂生成一个线程
// 注意,这里把Worker本身作为Runnable传递给线程工厂
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
// 实现Runbale的run方法
public void run() {
// 调用ThreadPoolExecutor的runWorker()方法执行线程
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
属性
*******************************************************************
/**
* 下面都是线程池的生命周期的属性
*
*/
// 初始状态为RUNNING
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;
/*** 线程池的状态 ***/
private static final int RUNNING = -1 << COUNT_BITS;
// 执行shutdown()后会把状态修改为SHUTDOWN
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 执行shutdownNow()方法时,会把线程池修改为stop状态,同时标记所有线程为中断状态
private static final int STOP = 1 << COUNT_BITS;
// 当执行shutdown()或shotdownNow()之后,所有任务中已中止,且工作线程数量为0,就会进入这个状态
// tryTerminate() 函数中可见
private static final int TIDYING = 2 << COUNT_BITS;
// 修改状态为TIDYING后执行terminated()方法,最后修改状态为TERMINATED,标志线程真正消亡了
// tryTerminate() 函数中可见
private static final int TERMINATED = 3 << COUNT_BITS;
*******************************************************************
/**
* 任务队列(构造参数之一)
* 当正在运行的线程数大于或等于核心线程的时候,任务来了先进入任务队列中的
* 这个队列必须是阻塞队列,所以像ConcurrentHashMap就不能作为参数
* ConcurrentHashMap是线程安全的队列,但是不是阻塞队列
*/
private final BlockingQueue<Runnable> workQueue;
private final ReentrantLock mainLock = new ReentrantLock();
/**
* 处于运行中的线程数量
* 例如判断运行中的线程数量是否大于等于核心线程,如果是,那就入任务队列
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
private final Condition termination = mainLock.newCondition();
/** 工作线程历史最大数量:也是线程池 同时处于运行中的线程数量最大是多少 */
private int largestPoolSize;
/** 正常完成的任务数量:也是线程池 正常完成的线程数量 */
private long completedTaskCount;
/**
* 线程工厂 (构造参数之一)
* {@link java.util.concurrent.Executors}
* 默认使用的是Executors工具类中的DefaultThreadFactory类,
* 这个类有一个缺点,创建的线程名称是自动生成的,无法自定义以区别不同的线程
* 并且这个类都是非守护线程
* 如果要自定义工厂,可以自己实现一个ThreadFactory工厂,然后把名称和守护线程作为构造方法当参数
*/
private volatile ThreadFactory threadFactory;
/**
* 拒绝策略(构造参数之一)
* 拒绝策略表示当任务队列满了且线程数也达到最大了,这时候再新加任务,线程池已经无法承受了,
* 这些新来的任务应该按什么逻辑来处理
* 常用的拒绝策略有丢弃当前任务、丢弃最老的任务、抛出异常、调用者自己处理等待
* 默认的拒绝策略是抛出异常,即线程池无法承载了,调用者再往里面添加任务会抛出异常
* 默认的拒绝车辆虽然比较简单粗暴,但是相对丢弃任务策略明显要好很多,最起码调用者
*自己可以捕获这个异常在进行二次处理
*/
private volatile RejectedExecutionHandler handler;
/**
* 线程保持空闲时间(构造参数之一)
* 默认情况下,此参数仅当正在运行的线程大于核心线程时才有效,即针对非核心线程
* 但是,如果allowCoreThreadTimeOut被设置了true,针对核心线程也有效
* 即当任务队列为空时,线程保持多久才会销毁,
* 内部主要通过阻塞队列待超时的poll(timeout,unit)方法来实现
*/
private volatile long keepAliveTime;
// 是否允许核心线程设置超时,默认是不允许
private volatile boolean allowCoreThreadTimeOut;
/**
* 核心线程数(构造参数之一)
* 当正在运行的线程数小于核心线程时,来一个任务就创建一个核心线程
* 当正在运行的线程大于或等于核心线程数时,任务来了先不创建线程而是丢入阻塞任务队列中
*/
private volatile int corePoolSize;
/**
* 最大线程数(构造参数之一)
* 当任务队列满了时,来一个任务才创建非核心线程,但不能超过最大线程数
*/
private volatile int maximumPoolSize;
/**
* 默认的拒绝策略,任务满了会直接抛出RejectedExecutionException异常
* (构造参数之一)
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
private final AccessControlContext acc;
构造方法
- 四个构造方法
/** 初始化构造方法一:采用默认线程工厂和默认拒绝策略,其他自定义 */
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/** 初始化构造方法二:采用默认拒绝策略,其他自定义 */
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/** 初始化构造方法三: 采用默认工厂,其他自定义*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
/** 初始化构造方法四: 线程工厂自定义、拒绝策略自定义*/
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.acc = System.getSecurityManager() == null ?
null :AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
//{@link java.util.concurrent.Executors.DefaultThreadFactory}
// 默认线程工厂
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
// 线程组
private final ThreadGroup group;
// 线程池名称自增
private final AtomicInteger threadNumber = new AtomicInteger(1);
// 线程池名称前缀
private final String namePrefix;
DefaultThreadFactory() {
// 获取安全管理器
SecurityManager s = System.getSecurityManager();
// 如果安全管理器不为null就获取安全管理器中的线程组,否则获取当前线程的线程组
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
// 初始化线程池名称前缀
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
// 设置守护线程为 无
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
// 设置默认线程优先级为 5
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
主要方法
1、线程池生命周期的方法
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvJtecD1-1579166492728)(
]
-
)
-
-
shudown() 关闭线程池
-
shudownNow() 立即关闭线程池
-
tryTerminate() 尝试终止线程池
// 线程池的状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 线程池中工作线程的数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 计算ctl的值,等于运行状态“加上” 线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; }
/** 关闭线程池,自旋+CAD所以一定可以关闭,并把所有线程设置为中断状态 */
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
// 加 主锁
mainLock.lock();
try {
// 检查权限
checkShutdownAccess();
// 修改状态为SHUTDOWN,采用自旋+CAS
advanceRunState(SHUTDOWN);
// 标记空闲线程为中断状态
interruptIdleWorkers();
// 为ScheduledThreadPoolExecutor 预留的
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
// 释放主锁
mainLock.unlock();
}
tryTerminate();
}
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
// 如果状态大于SHUDOWN,或者修改SHUTDOWN成功了,才会break出自旋
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
/** 立即关闭线程池*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
// 加 主锁
mainLock.lock();
try {
// 权限检查
checkShutdownAccess();
// 自旋+CAS 让线程进入STOP状态
advanceRunState(STOP);
// 标记空闲线程为中断状态
interruptWorkers();
// 把任务队列加入到一个新的队列保存到 tasks
tasks = drainQueue();
} finally {
// 释放主锁
mainLock.unlock();
}
tryTerminate();
return tasks;
}
/** */
final void tryTerminate() {
for (;;) {
// 获得线程池状态
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
// 1.如果线程池是RUNNING状态
// 2.如果线程池是TIDYING或TERMINATED状态
// 3.如果是SHOTDOWN状态且任务队列不为空
// 符合上面任何一点,则直接返回,不进入下面代码
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
// 工作线程数量不为0,
// 尝试中断空闲线程,然后直接返回
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
// 加主锁
mainLock.lock();
try {
// CAS更新修改状态为TIDYING
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 更新成功,执行terminated()钩子方法
terminated();
} finally {
// 强制更新状态为TERMINATED,这里不用CAS
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
// 释放主锁
mainLock.unlock();
}
// else retry on failed CAS
}
}
2、线程的执行方法
- execute():线程池提交任务的方法之一,也是最核心的方法,会根据核心线程数量、最大数量、任务队列大小,
- 先进行添加核心线程(添加到线程HashSet集合,此次会考虑容量),添加成功就会采用核心线程方式CAS启动任务
- 如果添加失败,那么就加入等待队列
- 加入任务队列成功,就会去CAS添加非核心线程(添加到线程HashSet集合,此次会考虑容量),添加成功,然后就会启动一次线程(加锁启动),启动失败就直接删除添加到HashSet集合中的线程
- 如果加入任务队列也失败,就会去CAS添加非核心线程(添加到线程HashSet集合),添加成功,然后去启动一次线程(加锁启动),如果启动失败,就直接采用拒绝策略
- 根据上面情况总结:
- 只要能加入队列,那么任务早晚会被运行,也不会被拒绝。
- 加入队列也失败,只要线程加入到工作线程集合,启动一次任务还是失败,那么肯定采用拒绝策略了
- addWorker():创建一个工作线程,并去启动,会做各种线程池状态和工作线程数量检测
- 这里会做线程池最大容量检查,true检查核心数量,false检查最大容量,如果不符合要求就会直接返回(但是如果加入到队列的话,是不影响的,所以LinkedBlockingQueue无界的,那么是没有容量限制的,maxSize是无效的)
- runWorker() :真正执行任务的方法
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();
// 1、如果线程少于 corePoolSize,尝试以给定的命令作为第一个任务启动新线程,对于 addWorker 的调用原子地检查 runState 和 workerCount,从而通过返回 false 来防止不应该添加线程的情况下发出错误警报;
if (workerCountOf(c) < corePoolSize) {
// 添加一个工作线程(核心)
if (addWorker(command, true))
// 核心线程已启动,返回成功
return;
// 添加工作线程(核心)失败,重新获取控制变量
c = ctl.get();
}
// 2、如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程(因为现有线程自上次检查后就已死亡)或自进入此方法以来池已关闭。因此,我么重新检查状态,如果停止,并在必要时回滚排队,如果已停止,或者再没有线程的情况下启动新线程;
if (isRunning(c) && workQueue.offer(command)) {
// 达到了核心线程最大数量,且线程池也是运行状态,就任务入队列
// 重新获取线程池状态,防止进入任务后线程池关闭
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
// 重新检查线程状态不是运行状态,就从工作队列中删除,然后抵达都用拒绝策略
reject(command);
else if (workerCountOf(recheck) == 0)
// 容错检查,工作线程数量是否为0,如果为0就创建一个
addWorker(null, false);
}
// 3、如果无法将任务排队,则尝试添加一个新线程,如果失败了,我们知道我们被关闭或已达到最大线程,因此拒绝该任务
// 任务入队列失败,尝试创建工作线程(非核心),失败则拒绝
else if (!addWorker(command, false))
reject(command);
}
/**
* 加入工作线程
* core代表加入的是 核心线程还是非核心线程
*/
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;
//循环检查数量及对工作线程数量+1
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
// 工作线程数量检查
return false;
if (compareAndIncrementWorkerCount(c))
// 尝试更新数量,成功跳出自定义标记块retry
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
// 再次获取状态
// 如果线程池状态有变化,跳过不执行下面代码(如果有的话),然后重新for循环
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// 如果上面的条件满足,会把工作线程数量+1
boolean workerStarted = false;// 标记线程是否已经启动成功,如果没成功会执行移除方法
boolean workerAdded = false;//标记添加到Woker的HashSet工作集合是否成功,成功了才启动线程
Worker w = null;
try {
// 创建一个工作线程(Worker继承了AQS,实现了Runnable)
w = new Worker(firstTask);
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 rs = runStateOf(ctl.get());
// 再次检查线程池状态
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 检测线程是否已经激活(启动),如果启动抛出IllegalThreadStateException异常
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 加入到HashSet工作线程集合中
workers.add(w);
// 获取工作线程集合数量(largestPoolSize只可在主锁下使用)
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
// 标记添加成功
workerAdded = true;
}
} finally {
// 释放-主锁
mainLock.unlock();
}
if (workerAdded) {
// 启动线程,此处执行的是Worker里面的run(),
// Worker类中的run调用的是runWorker();
t.start();
// 设置为已启动
workerStarted = true;
}
}
} finally {
if (! workerStarted)
// 线程启动失败,执行失败方法
//移除Woker的HashSet中的w线程,如果有的话,数量-1,tryTerminate()方法等
addWorkerFailed(w);
}
// 返回启动状态,true 成功,false 失败
return workerStarted;
}
/**
* Worker线程类,run()方法中调用此方法进行启动线程
*/
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();//当前线程
Runnable task = w.firstTask;//缓存当前待运行线程
w.firstTask = null;//GC
// 强制释放锁,(shutdown()里面有加锁)
// 相当于无视那边的中断标记
w.unlock(); // allow interrupts
boolean completedAbruptly = true;// 是否突然完成了
try {
// 如果参数的Woker线程中的任务线程是null,就会直接从队列中获取
// 只要还能取到任务,这就是一个死循环
while (task != null || (task = getTask()) != null) {
// 对当前Work加锁
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 {
// 开始真正执行任务了。
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,然后重新从队列中获取
task = null;
// 任务执行完成,就completedTasks加1
w.completedTasks++;
// 释放当前work线程锁
w.unlock();
}
}
completedAbruptly = false;// 没有突然完成,正常完成了任务
} finally {
// 到这里要么是突然完成,要么是正常完成了队列的任务,
// 如果是突然完成的(也就是其他地方完成 或者是异常了等情况),就会直接减少ctl值
// 如果是正常完成,就更新completedTaskCount值,并移除worker集合中当前的worker
// 等等其他逻辑
processWorkerExit(w, completedAbruptly);
}
}
/*
* {@link java.util.concurrent.ThreadPoolExecutor#runWorker(ThreadPoolExecutor.Worker)}
* 从任务队列中获取任务线程
*/
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 获取线程池状态
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// 1.如果线程池关闭了且线程池已经停止了,说明线程是STOP状态,立即退出
// 2.如果线程池关闭了,且任务队列为null,没有任务了直接立即退出
// 符合上面任何一点就,CAS修改Woker集合数量-1,然后返回null
decrementWorkerCount();
return null;
}
// 获得工作线程数量
int wc = workerCountOf(c);
// Are workers subject to culling?
// 是否允许超时机制
// 1、核心线程 配置了allowCoreThreadTimeOut=true
// 2、工作线程数量超过了核心线程数量
// 注意:非核心线程是一定有超时的,这里的超时其实是指取任务的超时
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 超时了,减少工作线程数量 ,并且返回 null
if (compareAndDecrementWorkerCount(c))
return null;
// 减少工作数量失败,就重试
continue;
}
try {
// 真正开始取任务了,
// 会根据timed来确定采用 poll超时 还是take进行阻塞等待任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
// 获得到了任务,直接返回任务
return r;
timedOut = true;
} catch (InterruptedException retry) {
// 捕捉到了中断异常,
// 中断标记是在调用shutdown()或shutdownNow()的时候设置进去的
// 此时,会回到for循环的第一个if处判断线程池状态,是否要返回null
timedOut = false;
}
}
}
3、提交线程
- 都是父类-抽象类AbstractExecutorService的方法
- 三个不同的submit方法
/** 提交线程,并且执行execute,返回Future,或者不返回 */
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
//等于new FutureTask<T>(callable),把普通任务包装成FutureTask
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
/** 提交线程,并且执行execut,返回Future<?> */
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);//见下
execute(ftask);
return ftask;
}
/** 提交线程,并且执行execute,返回包装了result的future,或不返回 */
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;
}
{@link java.util.concurrent.futureTask 的构造方法}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
{@link java.util.concurrent.Executors#callable}}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
{@link java.util.concurrent.Executors.RunnableAdapter 的构造方法}}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}