java中有几种实现异步的方式(FutureTask/ListenableFuture/CompletableFuture)
这篇介绍的是ListenableFuture,相比FutureTask,本质上只是增加了任务的回调函数,这个是google框架里面的一个东西,我用的版本是guava-27.0-jre.jar
首先还是说使用:
public class ListenableFutureTest {
public static void main(String[] args) {
testListenFuture();
}
public static void testListenFuture() {
System.out.println("主线程start");
ListeningExecutorService pool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
Task task1 = new Task();
task1.args = "task1";
Task task2 = new Task();
task2.args = "task2";
ListenableFuture future = pool.submit(task1);
ListenableFuture future2 = pool.submit(task2);
future2.addListener(() -> System.out.println("addListener 不能带返回值"), pool);
/**
* FutureCallBack接口可以对每个任务的成功或失败单独做出响应
*/
FutureCallback futureCallback = new FutureCallback() {
@Override
public void onSuccess(String result) {
System.out.println("Futures.addCallback 能带返回值:" + result);
}
@Override
public void onFailure(Throwable t) {
System.out.println("出错,业务回滚或补偿");
}
};
//为任务绑定回调接口
Futures.addCallback(future, futureCallback, pool);
System.out.println("主线程end");
}
}
class Task implements Callable {
String args;
@Override
public String call() throws Exception {
Thread.sleep(1000);
System.out.println("任务:" + args);
return "dong";
}
}
future2.addListener(() -> System.out.println(“addListener 不能带返回值”), pool);
Futures.addCallback(future, futureCallback, pool);
两种方法都可以,一会说一下原理,其实Futures.addCallback里面也是调用addListener
然后从上到下说一下原理:
上一篇直接用的是Thread(futureTask).start()去执行一个任务
这一篇用了java中的线程池-ThreadPoolExecutor,里面主要是使用execute去执行任务的
MoreExecutors.listeningDecorator就是包装了一下ThreadPoolExecutor,目的是为了使用ListenableFuture
private static class ListeningDecorator extends AbstractListeningExecutorService {
private final ExecutorService delegate;
ListeningDecorator(ExecutorService delegate) {
this.delegate = (ExecutorService)Preconditions.checkNotNull(delegate);
}
public final void execute(Runnable command) {
this.delegate.execute(command);
}
}
这里的delegate就是ThreadPoolExecutor
虽然还重写了execute,不过还是直接调用ThreadPoolExecutor里面的execute
ListeningExecutorService pool=MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
这样一个执行器就被new出来了,现在需要往里面放任务了
ListenableFuture future = pool.submit(task1);看看submit代码
public ListenableFuture submit(Callable task) {
return (ListenableFuture)super.submit(task);
}
然后调用父类的submit
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
这里会调用重写的newTaskFor
protected final RunnableFuture newTaskFor(Callable callable) {
return TrustedListenableFutureTask.create(callable);
}
class TrustedListenableFutureTask extends TrustedFuture implements RunnableFuture {
private volatile InterruptibleTask> task;
static TrustedListenableFutureTask create(Callable callable) {
return new TrustedListenableFutureTask(callable);
}
TrustedListenableFutureTask(Callable callable) {
this.task = new TrustedListenableFutureTask.TrustedFutureInterruptibleTask(callable);
}
public void run() {
InterruptibleTask localTask = this.task;
if (localTask != null) {
localTask.run();
}
this.task = null;
}
}
创建了一个TrustedListenableFutureTask,里面有个task是TrustedFutureInterruptibleAsyncTask
这里重写了Runnable的run方法,调用的就是这个task得run方法(也就是我们真正的任务)
private final class TrustedFutureInterruptibleAsyncTask extends InterruptibleTask> {
private final AsyncCallable callable;
TrustedFutureInterruptibleAsyncTask(AsyncCallable callable) {
this.callable = (AsyncCallable)Preconditions.checkNotNull(callable);
}
}
RunnableFuture ftask = newTaskFor(task);
所以这里返回的是一个RunnableFuture,本质其实是TrustedListenableFutureTask(每个任务都有这么一个future)
execute(ftask);
然后会调用execute,让线程池中某个线程去执行
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)) {
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);
}
再说一下addListener,其实就是给任务增加一个回调函数
future2.addListener(() -> System.out.println(“addListener 不能带返回值”), pool);
这里调用的是TrustedListenableFutureTask的addListener
实际上调用的是父类AbstractFuture的addListener
public void addListener(Runnable listener, Executor executor) {
checkNotNull(listener, "Runnable was null.");
checkNotNull(executor, "Executor was null.");
if (!isDone()) {
Listener oldHead = listeners;
if (oldHead != Listener.TOMBSTONE) {
Listener newNode = new Listener(listener, executor);
do {
newNode.next = oldHead;
if (ATOMIC_HELPER.casListeners(this, oldHead, newNode)) {
return;
}
oldHead = listeners; // re-read
} while (oldHead != Listener.TOMBSTONE);
}
}
// If we get here then the Listener TOMBSTONE was set, which means the future is done, call
// the listener.
executeListener(listener, executor);
}
如果这个任务已经完成,执行executeListener
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException var3) {
log.log(java.util.logging.Level.SEVERE, "RuntimeException while executing runnable " + runnable + " with executor " + executor, var3);
}
}
这里就是调用执行器的execute方法,相当于给线程池扔一个任务,毕竟回调函数也是一个任务
如果这个任务没有完成,那么把回调函数保存起来,用一个链表保存,链表的头结点就是listener,这个listener里面的回调函数在哪执行呢?在任务执行完之后,我文章最后再说这个问题。
ATOMIC_HELPER.casListeners(this, oldHead, newNode)是给listener赋值的原子操作。
private static final class Listener {
static final Listener TOMBSTONE = new Listener(null, null);
final Runnable task;
final Executor executor;
// writes to next are made visible by subsequent CAS's on the listeners field
@Nullable Listener next;
Listener(Runnable task, Executor executor) {
this.task = task;
this.executor = executor;
}
}
为什么要用链表呢?因为一个任务可以有多个回调函数
再来看看Futures.addCallback(future, futureCallback, pool);
public static void addCallback(
final ListenableFuture future,
final FutureCallback super V> callback,
Executor executor) {
Preconditions.checkNotNull(callback);
future.addListener(new CallbackListener(future, callback), executor);
}
底层用CallbackListener封装了一下,还是调用了addListener
为什么要封装一下呢?因为要拿到任务的返回值
private static final class CallbackListener implements Runnable {
final Future future;
final FutureCallback super V> callback;
CallbackListener(Future future, FutureCallback super V> callback) {
this.future = future;
this.callback = callback;
}
@Override
public void run() {
final V value;
try {
value = getDone(future);
} catch (ExecutionException e) {
callback.onFailure(e.getCause());
return;
} catch (RuntimeException | Error e) {
callback.onFailure(e);
return;
}
callback.onSuccess(value);
}
}
在这个run方法里面就调用getDone等待返回值,如果有异常就调用callback.onFailure,没有异常就调动callback.onSuccess(value);
这两个方法都是你传入的,这样就能接收到任务的返回值了
public static V getDone(Future future) throws ExecutionException {
checkState(future.isDone(), "Future was expected to be done: %s", future);
return getUninterruptibly(future);
}
public static V getUninterruptibly(Future future) throws ExecutionException {
boolean interrupted = false;
try {
while (true) {
try {
return future.get();
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
future.get()就是到等待任务执行结束
现在接着说listener中的回调函数在哪执行的
private final class TrustedFutureInterruptibleTask extends InterruptibleTask {
private final Callable callable;
@Override
void afterRanInterruptibly(V result, Throwable error) {
if (error == null) {
TrustedListenableFutureTask.this.set(result);
} else {
setException(error);
}
}
}
在任务执行完之后,这里调用了set方法
protected boolean set(@Nullable V value) {
Object valueToSet = value == null ? NULL : value;
if (ATOMIC_HELPER.casValue(this, null, valueToSet)) {
complete(this);
return true;
}
return false;
}
然后又调用了comlete
private static void complete(AbstractFuture> future) {
Listener next = null;
outer:
while (true) {
future.releaseWaiters();
next = future.clearListeners(next);
future = null;
while (next != null) {
Listener curr = next;
next = next.next;
Runnable task = curr.task;
if (task instanceof SetFuture) {
SetFuture> setFuture = (SetFuture>) task;
future = setFuture.owner;
if (future.value == setFuture) {
Object valueToSet = getFutureValue(setFuture.future);
if (ATOMIC_HELPER.casValue(future, setFuture, valueToSet)) {
continue outer;
}
}
// other wise the future we were trying to set is already done.
} else {
executeListener(task, curr.executor);
}
}
break;
}
}
就是在这里执行完所有的回调函数