项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现。
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class AddTask implements Callable{ private int a,b; public AddTask(int a, int b) { this.a = a; this.b = b; } @Override public Integer call() throws Exception { Integer result = a + b; return result; } public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newSingleThreadExecutor(); //JDK目前为止返回的都是FutureTask的实例 Future future = executor.submit(new AddTask(1, 2)); Integer result = future.get();// 只有当future的状态是已完成时(future.isDone() = true),get()方法才会返回 } }
Callable接口Runable接口可谓是兄弟关系,只不过Callable是带返回值的。
public interface Callable{ /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
接口函数及含义 :public interface Future
boolean cancel(boolean mayInterruptIfRunning)
取消当前执行的任务,如果已经执行完毕或者已经被取消/由于某种原因不能被取消 则取消任务失败。
参数mayInterruptIfRunning: 当任务正在执行,如果参数为true ,则尝试中断任务,否则让任务继续执行知道结束。
boolean isCancelled()
Returns {@code true} if this task was cancelled before it completed
* normally.
boolean isDone();
/**
* Returns {@code true} if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* {@code true}.
*
* @return {@code true} if this task completed
*/
V get() throws InterruptedException, ExecutionException;
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
由注释可以看出,当没有执行完成时,需要等待任务执行完成了才会将计算结果返回。
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
如果等待的时间超过设置的时间则会报 TimeoutException异常
public class FutureTask
由定义可以看出它实现了RunnableFuture接口,那么这个接口又是什么呢?看下面的接口定义,其实很简单
public interface RunnableFutureextends Runnable, Future { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
再回到FutureTask,它其实就是实现了Runnable和Future接口,FutureTask的执行是 状态转换的过程,源码中有七种状态如下:
* Possible state transitions: * NEW -> COMPLETING -> NORMAL * NEW -> COMPLETING -> EXCEPTIONAL * NEW -> CANCELLED * NEW -> INTERRUPTING -> INTERRUPTED */ 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;
当FutureTask刚刚被创建时,它的状态是NEW,其它状态查看源码。
其它成员变量:
/** The underlying callable; nulled out after running */ private Callablecallable; /** The result to return or exception to throw from get() */ private Object outcome; // non-volatile, protected by state reads/writes /** The thread running the callable; CASed during run() */ private volatile Thread runner; /** Treiber stack of waiting threads */ private volatile WaitNode waiters;
callable是待执行的任务,FutureTask 的 run()函数中执行callable中的任务。
outcome : 是callable的执行结果,当正常执行完成后会将结果set到outcome中
runner:是执行callable 的线程
WaitNode : 是的受阻塞的线程链表,当cancel一个任务后,阻塞的线程会被唤醒。
构造函数:
public FutureTask(Callablecallable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
从构造函数可以看出,不光可以通过callable构造FutureTask还可以通过Runnable接口转化为callable来构造。关键函数为黄色标记部分,Executors中的实现源码如下:
/** * A callable that runs given task and returns given result. */ private static final class RunnableAdapterimplements Callable { private final Runnable task; private final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } }
这里面不懂result到底有什么意义,明明就是预先设置好的。
其它具体的方法说明这里不再细说,里面用到了很多sun.misc.Unsafe中的方法以及其他SDK底层接口,后续有时间再学习。下面贴出了整个源码及说明
FutureTask简单应用:
public class FutureMain { public static void main(String[] args) throws ExecutionException, InterruptedException { //构造FutureTask FutureTaskfutureTask = new FutureTask (new CallableClass("xxx")); ExecutorService executorService = Executors.newFixedThreadPool(1); //执行FutureTask,发送请求 //在这里开启线程进行RealData的call()执行 executorService.submit(futureTask); System.out.println("请求完毕。。。"); try { //这里可以进行其他额外的操作,这里用sleep代替其他业务的处理 Thread.sleep(200); }catch (InterruptedException e) { e.printStackTrace(); } //获取call()方法的返回值 //如果此时call()方法没有执行完成,则依然会等待 System.out.println("真实数据:"+futureTask.get()); } }
www.kzo4326.cn
www.tso8557.cn
www.nwm1536.cn
www.tae4138.cn
www.dxc3579.cn
www.ffp5727.cn
www.lhb4836.cn
www.xdi0113.cn
www.bpa2365.cn
www.fks8445.cn
www.aht8537.cn
www.cun5054.cn
www.gdk7028.cn
www.ypk8666.cn
www.wan2959.cn
www.sit9945.cn
www.zmj4226.cn
www.ccn6233.cn
www.jck8045.cn
www.ckk6213.cn
www.mak1390.cn
www.vii0197.cn
www.pwj5001.cn
www.wvh4263.cn
www.mvg0339.cn
www.yif9712.cn
www.jta0960.cn
www.omx8816.cn
www.nlc4773.cn
www.dep9137.cn
www.vlq7732.cn
www.umg2515.cn
www.kog1435.cn
www.nxf9936.cn
www.hqh7518.cn
www.hij5984.cn
www.vui9639.cn
www.fzl7156.cn
www.wue0833.cn
www.dye6768.cn
www.ryh7899.cn
www.lij0467.cn
www.epv8502.cn
www.lru8400.cn
www.mtr5072.cn
www.kbs9896.cn
www.qfk7654.cn
www.myb6827.cn
www.tcr0461.cn
www.xua4102.cn
www.tzn6024.cn
www.kme4313.cn
www.bnb6875.cn
www.yio4898.cn
www.yat8046.cn