线程Thread即表示要执行的任务,又表示执行的机制。
Java并发包提供了一套“异步任务执行服务”机制,将“任务的提交”和“任务的执行”相分离。
任务执行服务涉及到的基本接口:
Runnable和Callable都是接口,Runnable没有返回结果,而Callable有,Runnable不会抛出异常,而Callable会。
Executor表示最简单的执行服务
public interface Executor {
void execute(Runnable command);
}
可以执行一个Runnable,没有返回结果。接口没有限定任务如何执行,可能是创建一个新线程,可能是复用线程池中的某个线程
ExecutorService扩展了Executor,定了更多服务
先来看submit方法,submit表示提交一个任务,返回值类型都是Future,返回后,只是表示任务已提交,不代表已执行,通过Future可以查询异步任务的状态、获取最终结果、取消任务等。
public interface ExecutorService extends Executor {
// 对于Callable,任务最终有个返回值
Future submit(Callable task);
// Runnable是没有返回值的,但可以提供一个结果,在异步任务结束时返回
Future submit(Runnable task, T result);
// 最终返回null
Future> submit(Runnable task);
}
再来看看Future的定义:
public interface Future<V> {
// 用于取消异步任务,如果任务已完成、或已取消、或由于某种原因不能取消,返回false,否则返回true
// 如果任务还未开始,则不再运行。如果任务已经在运行,则不一定能取消
// 参数mayInterruptIfRunning表示,如果任务正在执行,是否调用interrupt方法中断线程,如果为false就不会,如果为true就会尝试中断线程,中断不一定能取消线程
boolean cancel(boolean mayInterruptIfRunning);
// 表示任务是否被取消,只要cancel方法返回了true,随后的isCancelled方法都会返回true,即使执行任务的线程还未真正结束
boolean isCancelled();
// 表示任务是否结算,不管什么原因导致结束的
boolean isDone();
// 返回执行结果,如果任务是Runnable且没有提供结果,返回null
// 任务被取消了,会抛出CancellationException
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
public class Test {
static class Task implements Callable {
@Override
public Integer call() throws Exception {
int sleepSeconds = new Random().nextInt(1000);
Thread.sleep(sleepSeconds);
return sleepSeconds;
}
}
public static void main(String[] args) throws InterruptedException {
// 创建一个任务执行服务
ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(new Task());
Thread.sleep(100);
try {
System.out.println(future.get());
} catch (ExecutionException e) {
e.printStackTrace();
}
// 关闭任务执行服务
executor.shutdown();
}
}
ExecutorService还有如下几个方法:
public interface ExecutorService extends Executor {
// 不再接受新任务,但已提交的任务会继续执行,即使任务还未执行
void shutdown();
// 不接口新任务,且会终止已提交但未执行的任务,对于正在执行的任务,一般会调用线程的interrupt方法尝试中断
// 返回已提交但尚未执行的任务列表
List shutdownNow();
// showdown和showdownNow不会阻塞,它们返回后不代表所有任务都已结束,但isShutdown会返回ture
boolean isShutdown();
// 除非首先调用shutdown或shutdownNow,否则isTerminated永不为true。
// 当调用shutdown()方法后,并且所有提交的任务完成后返回为true;
// 当调用shutdownNow()方法后,成功停止后返回为true;
boolean isTerminated();
// 等待所有任务结束,可以限定等待的时间
// 如果超时前所有任务都结束了,则返回true,否则返回false
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
// 等待所有任务完成,返回Future列表
// 每个Future的isDone都返回true,不过isDone不代表任务执行成功了,可能是被取消了
List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException;
List> invokeAll(Collection extends Callable> tasks,
long timeout, TimeUnit unit) throws InterruptedException;
// 只要有一个任务返回成功了,就会返回该任务的结果,其他任务会被取消
T invokeAny(Collection extends Callable> tasks)
throws InterruptedException, ExecutionException;
T invokeAny(Collection extends Callable> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
ExecutorService的主要实现类是ThreadPoolExecutor,它是基于线程实现的,继承于AbstractExecutorService
。AbstractExecutorService是一个抽象类,实现了ExecutorService的部分方法。
AbstractExecutorService提供了submit、invokeAll、invokeAny的默认实现,子类需要实现其他方法。
除了execute,其他方法都与执行服务的生命周期管理有关,submit/invokeAll/invokeAny最终都会调用execute,execute决定了到底如何执行任务。
我们可以先看看submit方法
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
调用newTaskFor生成了一个RunnableFuture,RunnableFuture是一个接口,既扩展了Runnable,又扩展了Future,没有定义新的方法。作为Runnable它表示要执行的任务,传递给execute进行执行;作为Future它表示任务执行的异步结果。
我们再看看newTaskFor
protected RunnableFuture newTaskFor(Callable callable) {
return new FutureTask(callable);
}
FutureTask实现了RunnableFuture接口
public class FutureTask<V> implements RunnableFuture<V> {
// 表示状态
private volatile int state;
// 刚开始的状态或任务在运行
private static final int NEW = 0;
// 临时状态,任务即将结果,在设置结果
private static final int COMPLETING = 1;
// 任务正常执行完成
private static final int NORMAL = 2;
// 任务执行抛出异常结束
private static final int EXCEPTIONAL = 3;
// 任务被取消
private static final int CANCELLED = 4;
// 任务在被中断
private static final int INTERRUPTING = 5;
// 任务被中断
private static final int INTERRUPTED = 6;
// 表示待执行的任务
private Callable callable;
// 表示最终的执行结果或异常
private Object outcome;
// 表示运行任务的线程
private volatile Thread runner;
// 单向链表,表示等待任务执行结果的线程
private volatile WaitNode waiters;
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
// 初始化状态
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
// 如果传入的是runnable,则转换为callable
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
}
任务执行服务会使用一个线程执行FutureTask的run方法
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 {
// 调用callable的call方法
result = c.call();
ran = true;
} catch (Throwable ex) {
// 捕捉异常,异常保存到outcome并调用finishCompletion唤醒所有等待结果的线程
result = null;
ran = false;
setException(ex);
}
// 设置结果,保存到outcome并调用finishCompletion唤醒所有等待结果的线程
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);
}
}
任务提交者,通过get方法获取结果,
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
// 如果任务还未执行完毕就等待
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
// 调用report报告结果,report根据状态返回结果或抛出异常
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}