1.submit与execute方法的区别
//ExecutorService中定义
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
//Executor中定义
void execute(Runnable command);
//AbstractExecutorService中实现
/**
* 提交任务 -Runnable
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException(); //校验
RunnableFuture<Void> ftask = newTaskFor(task, null);//创建Future
execute(ftask); //调用execute方法 这里未实现
return ftask; //返回当前Future
}
/**
* 提交任务 -Runnable result
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();//校验
RunnableFuture<T> ftask = newTaskFor(task, result);//创建Future
execute(ftask); //调用execute方法 这里未实现
return ftask; //返回当前Future
}
/**
* 提交任务 -Callable
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException(); //校验
RunnableFuture<T> ftask = newTaskFor(task); //创建Future
execute(ftask); //调用execute方法 这里未实现
return ftask; //返回当前Future
}
从接口定义来看,execute只能提交Runnable类型的任务,而且任务提交无返回值。而submit可以提交Runnable或者Callable类型的任务,而且会返回一个Future结果,submit方法会把提交的任务封装到一个RunnableFuture中然后调用execute方法提交任务。
1.1submit方法中Runnable任务是如何被封装成RunnableFuture的
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW;
}
public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
if (action == null)
throw new NullPointerException();
return new Callable<Object>() {
public Object call() throws Exception { return action.run(); }};
}
看代码可知,是将新建一个Callable实现call方法的代码就是直接调用Runnable的run方法实现,之后再将Callable封装到FutureTask中
2.线程的重复使用?
一般线程开启后执行run方法,run方法执行结束后线程就关闭了,那么ThreadPoolExecutor是怎么让线程重复使用的呢?
private boolean addWorker(Runnable firstTask, boolean core) {
//省略代码-----
w = new Worker(firstTask);
final Thread t = w.thread;
//省略代码-----
}
从代码中可知,线程池添加新线程的时候时从Worker中拿的,而Worker创建的时候接收了我们提交的任务,让我们看一下Worker时怎么创建的吧
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
private static final long serialVersionUID = 6138294804551838833L;
final Thread thread;
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
//Worker的run方法调用的是ThreadPoolExecutor的runWorker方法
public void run() {
runWorker(this);
}
//-----------
}
观察代码,可知Worker继承了AbstractQueuedSynchronizer和Runnable,内部还定义了Thread和Runnable两个属性,在初始化的时候会接收任务到Runnable中,然后从线程工厂中获取到一个线程,并将自身对象赋值给线程,再将线程赋值到自己的Thread属性中。
豆豆:这关系真乱
理一下,也就是worker.thread.start()线程开启之后,会调用worker对象中的run方法。也就是会开启一个线程,去执行runWorker(worker)方法,Worker类时ThreadPoolExecutor的一个内部类,调用的runWorker方法其实是在ThreadPoolExecutor中定义的。
/**
* 线程执行
*/
final void runWorker(Worker w) {
Thread wt = Thread.currentThread(); //当前线程
//取出需要执行的任务
Runnable task = w.firstTask;
w.firstTask = null; //取出之后将firstTask置空
w.unlock(); //豆豆:不管咋说,先unlock一下
boolean completedAbruptly = true;
try {
//如果task不是null,或者去队列中取任务,注意这里会阻塞
while (task != null || (task = getTask()) != null) {
//这个lock在这里是为了如果线程被中断,那么会抛出InterruptedException,而退出循环,结束线程
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方法
} 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 {
//Worker退出
processWorkerExit(w, completedAbruptly);
}
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // 若为false则执行成功 否则则是发生了异常
decrementWorkerCount(); //发生异常,执行被中断设置ctl值为-1 若无异常不执行
final ReentrantLock mainLock = this.mainLock; //获取锁
mainLock.lock(); //加锁
try {
completedTaskCount += w.completedTasks;
workers.remove(w); //移除任务w
} finally {
mainLock.unlock(); //解锁
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//又执行addWorker --- 递归了------
addWorker(null, false);
}
}
原来这里会重复调用addWorker,一直去工作,不过当没有任务的时候调用getTask会阻塞线程看一下getTask代码吧
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
//检查线程池的状态,如果已经是STOP及以上的状态,或者已经SHUTDOWN,队列也是空的时候,直接return null,并将Worker数量-1
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 注意这里的allowCoreThreadTimeOut参数,字面意思是否允许核心线程超时,即如果我们设置为false,那么只有当线程数wc大于corePoolSize的时候才会超时
//更直接的意思就是,如果设置allowCoreThreadTimeOut为false,那么线程池在达到corePoolSize个工作线程之前,不会让闲置的工作线程退出
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//确认超时,将Worker数-1,然后返回
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//从队列中取任务,根据timed选择是有时间期限的等待还是无时间期限的等待
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}