Callable、Future、FutureTask基本介绍
直接继承Thread或者实现Runnable接口都可以创建线程,但是这两种方法都有一个问题就是:没有返回值,也就是不能获取执行完的结果。
因此jdk1.5就提供了Callable接口来实现这一场景,而Future和FutureTask就可以和Callable接口配合起来使用。
Callable和Runnable的区别
Runnable不能返回一个返回值,不能抛出 checked Exception。
Callable的call方法可以有返回值,可以声明抛出异常。
Callable 配合的有一个 Future 类,通过 Future 可以了解任务执行情况,或者取消任务的执行,还可获取任务执行的结果,这些功能都是 Runnable 做不到的,Callable 的功能要比 Runnable 强大。
FutureTask的父类Future介绍
Future最常用的实现是:FutureTask(由于他继承的RunnableFuture实现了Runnable和Future)
boolean cancel (boolean mayInterruptIfRunning) :取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束。
boolean isCancelled () :任务是否已经取消,任务正常完成前将其取消,则返回 true。
boolean isDone () :任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true。
V get () throws InterruptedException, ExecutionException :等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException。
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException :同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException
Future的注意事项
当 for 循环批量获取 Future 的结果时容易长时间阻塞,get 方法调用时应使用 timeout 限制。
Future 的生命周期不能后退。一旦完成了任务,它就永久停在了“已完成”的状态,不能从头再来。
Future的缺陷
并发执行多任务 :Future只提供了get()方法来获取结果,并且是阻塞的。所以,除了等待你别无他法;
无法对多个任务进行链式调用 :如果你希望在计算任务完成后执行特定动作,比如发邮件,但Future却没有提供这样的能力;
无法组合多个任务 :如果你运行了10个任务,并期望在它们全部执行结束后执行特定动作,那么在Future中这是无能为力的;
没有异常处理 :Future接口中没有关于异常处理的方法;
使用方式:把串行的任务并行化
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
public class FutureTest {
public static void main (String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> ft1 = new FutureTask <>(new T1Task ());
FutureTask<String> ft2 = new FutureTask <>(new T2Task ());
FutureTask<String> ft3 = new FutureTask <>(new T3Task ());
FutureTask<String> ft4 = new FutureTask <>(new T4Task ());
FutureTask<String> ft5 = new FutureTask <>(new T5Task ());
ExecutorService executorService = Executors.newFixedThreadPool(5 );
executorService.submit(ft1);
executorService.submit(ft2);
executorService.submit(ft3);
executorService.submit(ft4);
executorService.submit(ft5);
System.out.println(ft1.get());
System.out.println(ft2.get());
System.out.println(ft3.get());
System.out.println(ft4.get());
System.out.println(ft5.get());
executorService.shutdown();
}
static class T1Task implements Callable <String> {
@Override
public String call () throws Exception {
System.out.println("T1:任务正在执行..." );
TimeUnit.MILLISECONDS.sleep(50 );
return "T1:执行完成!" ;
}
}
static class T2Task implements Callable <String> {
@Override
public String call () throws Exception {
System.out.println("T2:任务正在执行..." );
TimeUnit.MILLISECONDS.sleep(50 );
return "T2:执行完成!" ;
}
}
static class T3Task implements Callable <String> {
@Override
public String call () throws Exception {
System.out.println("T3:任务正在执行..." );
TimeUnit.MILLISECONDS.sleep(50 );
return "T3:执行完成!" ;
}
}
static class T4Task implements Callable <String> {
@Override
public String call () throws Exception {
System.out.println("T4:任务正在执行..." );
TimeUnit.MILLISECONDS.sleep(50 );
return "T4:执行完成!" ;
}
}
static class T5Task implements Callable <String> {
@Override
public String call () throws Exception {
System.out.println("T5:任务正在执行..." );
TimeUnit.MILLISECONDS.sleep(50 );
return "T5:执行完成!" ;
}
}
}
运行结果
FutureTask的状态源码分析
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的构造方法源码分析
public FutureTask (Callable<V> callable) {
if (callable == null )
throw new NullPointerException ();
this .callable = callable;
this .state = NEW;
}
public FutureTask (Runnable runnable, V result) {
this .callable = Executors.callable(runnable, result);
this .state = NEW;
}
public static <T> Callable<T> callable (Runnable task, T result) {
if (task == null )
throw new NullPointerException ();
return new RunnableAdapter <T>(task, result);
}
static final class RunnableAdapter <T> implements Callable <T> {
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的run方法源码分析
public void run () {
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 {
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 setException (Throwable t) {
if (UNSAFE.compareAndSwapInt(this , stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this , stateOffset, EXCEPTIONAL);
finishCompletion();
}
}
private void finishCompletion () {
for (WaitNode q; (q = waiters) != null ;) {
if (UNSAFE.compareAndSwapObject(this , waitersOffset, q, null )) {
for (;;) {
Thread t = q.thread;
if (t != null ) {
q.thread = null ;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null )
break ;
q.next = null ;
q = next;
}
break ;
}
}
done();
callable = null ;
}
protected void set (V v) {
if (UNSAFE.compareAndSwapInt(this , stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this , stateOffset, NORMAL);
finishCompletion();
}
}
private void handlePossibleCancellationInterrupt (int s) {
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield();
}
FutureTask的get方法源码分析
public V get () throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false , 0L );
return report(s);
}
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 ();
return report(s);
}
private int awaitDone (boolean timed, long nanos)
throws InterruptedException {
final long = timed ? System.nanoTime() + nanos : 0L ;
WaitNode q = null ;
boolean queued = false ;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException ();
}
int s = state;
if (s > COMPLETING) {
if (q != null )
q.thread = null ;
return s;
}
else if (s == COMPLETING)
Thread.yield();
else if (q == null )
q = new WaitNode ();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this , waitersOffset,
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 );
}
}
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);
}
结束语
获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!
关注公众号,可以让你对MySQL、并发编程、spring源码有深入的了解!
关注公众号,后续持续高效的学习JVM!
这个公众号,无广告!!!每日更新!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!