1、了解线程池几个类之间的关系 (结合图看后面的分析)
FutureTask 继承 RunnableFuture , RunnableFuture 实现接口 Runnable
2、分析常用调用线程池代码(以下称为代码A)
ExecutorService es = Executors.newFixedThreadPool(15);
es.submit(new Callable(){
@Override
public String call() throws Exception {
return null;
}});
es.submit(new myThread());
1)首先我们看看Executors.newFixedThreadPool()这个方法的源码
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
}
2)再看看es.submit()这个方法是如何实现的
在源码中,我们会发现ThreadPoolExecutor并没有方法submit,它是调用了父类abstractExecutorService.submit()方法,源码如下
protected RunnableFuture newTaskFor(Runnable runnable, T value) {
return new FutureTask(runnable, value);
}
protected RunnableFuture newTaskFor(Callable callable) {
return new FutureTask(callable);
}
public Future> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public Future submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
而ThreadPoolExecutor类中是重写了execute()方法的,所以代码A中的es.submit实际上执行的是ThreadPoolExecutor.executor().
3)了解Callable 与 Runnable转换为FutureTask
FutureTask
static final class RunnableAdapter implements Callable {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
FutureTask
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
结果还是把Callable的call()方法丢到了Runnable的run()方法中 ,
看到里面的set(result)没有,就是通过一个全局变量,变相的返回线程执行结果,获取是FutureTask.get()方法。
4)再看看ThreadPoolExecutor.executor()是如何实现的 ,具体后续分析
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();
if (workerCountOf(c) < corePoolSize) {
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);
}
else if (!addWorker(command, false))
reject(command);
}
上面的addWorker(COMMAND,FLAG)方法中,满足条件会构建new Thread(FutureTask) t,调用t.start();
逻辑图
5)终于到最后了,可以说我最想说的话了 。
之前没看代码,狗日的以为Callable是个很神奇的东西,就是Thread的兄弟,使用起来也挺神秘,只见过再ExecutorService.submit()见到过 。
现在才知道,Callable仅仅只是为线程执行的时候能够返回对象,且仅仅只能在ExecutorService.submit()中使用,其他无卵用。
绕来绕去还是Thread与Runnable的start方法与run方法啊。