Runnable Callable Future FutureTask
(一)runnable 与Callable的区别
@FunctionalInterface public interface Runnable { public abstract void run(); } @FunctionalInterface public interface Callable<V> { V call() throws Exception; }
- call()方法可以有返回值,返回类型为泛型V,代表着支持所有类型的返回值。
- call()方法定义时声明了可以抛出异常:throws Exception,而run()则不行。
public interface Future<V> { /** 尝试取消执行此任务。如果任务已完成、已取消或由于其他原因无法取消,则此尝试将失败 */ boolean cancel(boolean mayInterruptIfRunning); /** 如果此任务在完成之前被取消,则返回True */ boolean isCancelled(); /** 如果此任务已完成,则返回{true}。完成可能是由于正常终止、异常或取消——在所有这些情况下,此方法都将返回{ true} */ boolean isDone(); /** 如果需要,等待计算完成,然后检索其结果,如果计算被取消,则返回计算结果@throws CancellationException 如果计算引发异常,则返回@throws ExecutionException 如果当前线程在等待时中断,则返回异常@throws InterruptedException */ V get() throws InterruptedException, ExecutionException; /** 如果需要,最多等待给定的时间以完成计算,然后检索其结果(如果可用) @param timeout等待的最长时间 @param unit超时参数的时间单位 */ V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
(二)Future与FutureTask
FutureTask实现了RunnableFuture接口,而RunnableFuture除开继承了Runnable外,还继承了Future接口.Future接口中主要提供了两类方法:获取任务执行结果的get方法以及取消任务的cancel方法.
在FutureTask出现之前,Java中的多线程编程执行任务后是不能获取执行结果的。而FutureTask整合了Runnable、Callable、Future三个接口,使得我们的多线程任务执行后可以异步获取到多线程的执行结果。FutureTask会将执行结束后的结果保存在成员变量:outcome中,等待获取执行结果的线程则读取outcome成员值即可。
public class FutureTask<V> implements RunnableFuture<V> { /** * 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; private Callable<V> callable; private Object outcome; // non-volatile, protected by state reads/writes private volatile Thread runner; private volatile WaitNode waiters; @SuppressWarnings("unchecked") 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); } public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } ... public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { if (unit == null) throw new NullPointerException(); int s = state; //如果状态小于COMPLETING,表示FutureTask任务还没完成,则调用awaitDone让当前线程等待 if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING) throw new TimeoutException(); return report(s); } public void run() { //r如果状态值state不是NEW,捉着设置runner值失败,直接返回 if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { //调用callable方法,获取结果 result = c.call(); //运行成功 ran = true; } catch (Throwable ex) { result = null; ran = false; //设置异常 setException(ex); } if (ran) //设置返回结果 set(result); } } finally { runner = null; int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } } protected void set(V v) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { //将结果赋值给outcome outcome = v; UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state finishCompletion(); } } private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { //如果当前线程设置了中断标记 if (Thread.interrupted()) { //从列表中移除节点q,并抛出中断异常 removeWaiter(q); throw new InterruptedException(); } int s = state; //如果状态已经完成,表示FutureTask任务已结束 if (s > COMPLETING) { if (q != null) q.thread = null; return s; } //还有一些后续操作没有完成,当前线程让出执行权 else if (s == COMPLETING) // cannot time out yet Thread.yield(); else if (q == null) q = new WaitNode(); else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, //timed为true表示需要设置超时 q.next = waiters, q); else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos); } else LockSupport.park(this); } } }
- submit与execute是否都可以接受异常,是否都有返回值
public interface Executor { /** * Executes the given command at some time in the future. The command * may execute in a new thread, in a pooled thread, or in the calling * thread, at the discretion of the {@code Executor} implementation. * * @param command the runnable task * @throws RejectedExecutionException if this task cannot be * accepted for execution * @throws NullPointerException if command is null */ void execute(Runnable command); }
execute方法是在executor接口中定义的,执行execute方法时,如果任务不可被接受,则抛出RejectedExecutionException。如果command是null,则抛出NullPointerException。但是执行runnable接口时,其run方法是不抛出异常的。
public interface ExecutorService extends Executor { <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); }
submit方法是在executorService接口中定义的,如果任务不可被接受,则抛出RejectedExecutionException。如果command是null,则抛出NullPointerException。submit执行时,会将Callable或者runnable接口封装成futureTask,然后调用futuretask的run方法,最后实际调用了futuretask内部的Callable成员变量的call方法。对于runnable接口封装成的futureTask,最后实际调用的是runnable的run方法。而对于Callable接口封装成的futureTask,最后实际调用的是Callable的call方法.
总结:execute方法接受的是runnable接口,是不会往外抛异常的。而submit方法,即可接受runnable接口,也可接受Callable接口。抛不抛异常看传入的接口类型。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)