接上一篇博客https://blog.csdn.net/qq_43605444/article/details/121569162?spm=1001.2014.3001.5501
7、Future、Callable接口Future接口定义了操作异步任务执行的一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
Callable接口中定义了需要有返回的任务需要实现的方法。
@FunctionalInterface public interface Callable{ V call() throws Exception; }
比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,过了一会才去获取子任务的执行结果。
7.1 获取异步任务执行结果示例代码:
public class GetTaskExecuteResult {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future result = executorService.submit(() -> {
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",start!");
TimeUnit.SECONDS.sleep(5);
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",end!");
return 10;
});
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName());
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + ",结果:" + result.get());
executorService.shutdown();
}
}
运行上面的代码,输出结果:
1637908879476,main 1637908879476,pool-1-thread-1,start! 1637908884482,pool-1-thread-1,end! 1637908879476,main,结果:10
代码中创建了一个线程池,调用线程池的submit方法执行任务,submit参数为Callable接口:表示需要执行的任务有返回值,submit方法返回一个Future对象,Future相当于一个凭证,可以在任意时间拿着这个凭证去获取对应任务的执行结果(调用其get方法),代码中调用了result.get()方法之后,此方法会阻塞当前线程直到任务执行结束。
7.2 超时获取异步任务执行结果可能任务执行比较耗时,比如耗时1分钟,我最多只能等待10秒,如果10秒还没返回,我就去做其他事情了。
刚好get有个超时的方法,声明如下:
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
示例代码:
public class GetTaskExecuteResultWhenTimeout {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future result = executorService.submit(() -> {
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",start!");
TimeUnit.SECONDS.sleep(5);
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",end!");
return 10;
});
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName());
try {
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + ",结果:" + result.get(3,TimeUnit.SECONDS));
} catch (TimeoutException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
运行上面的代码,输出结果:
1637909217527,main 1637909217528,pool-1-thread-1,start! java.util.concurrent.TimeoutException at java.util.concurrent.FutureTask.get(FutureTask.java:205) at com.juc.example2.GetTaskExecuteResultWhenTimeout.main(GetTaskExecuteResultWhenTimeout.java:24) 1637909222541,pool-1-thread-1,end!
任务执行中休眠了5秒,get方法获取执行结果,超时时间是3秒,3秒还未获取到结果,get触发了TimeoutException异常,当前线程从阻塞状态苏醒了。
7.3 Future其他方法介绍一下- cancel:取消在执行的任务,参数表示是否对执行的任务发送中断信号,方法声明如下:
boolean cancel(boolean mayInterruptIfRunning);
-
isCancelled:用来判断任务是否被取消
-
isDone:判断任务是否执行完毕。
cancel方法来个示例:
public class FutureCancelTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future result = executorService.submit(() -> {
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",start!");
TimeUnit.SECONDS.sleep(5);
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",end!");
return 10;
});
executorService.shutdown();
TimeUnit.SECONDS.sleep(1);
result.cancel(false);
System.out.println(result.isCancelled());
System.out.println(result.isDone());
TimeUnit.SECONDS.sleep(5);
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName());
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + ",结果:" + result.get());
executorService.shutdown();
}
}
运行上面的代码,输出结果:
1637909761085,pool-1-thread-1,start true true 1637909766092,pool-1-thread-1,end 1637909767101,main Exception in thread "main" java.util.concurrent.CancellationException at java.util.concurrent.FutureTask.report(FutureTask.java:121) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at com.juc.example2.FutureCancelTest.main(FutureCancelTest.java:38)
输出2个true,表示任务已被取消,已完成,最后调用get方法会触发CancellationException异常。
总结:从上面可以看出Future、Callable接口需要结合ExecutorService来使用,需要有线程池的支持。
8、FutureTask类FutureTask除了实现Future接口,还实现了Runnable接口,因此FutureTask可以交给Executor执行,也可以交给线程执行执行(Thread有个Runnable的构造方法),FutureTask表示带返回值结果的任务。
上面我们演示的是通过线程池执行任务然后获取执行结果。
这次我们通过FutureTask类,自己启动一个线程来获取执行结果,示例如下:
public class FutureTaskTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask(()->{
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",start!");
TimeUnit.SECONDS.sleep(5);
System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName()+",end!");
return 10;
});
System.out.println(System.currentTimeMillis()+","+Thread.currentThread().getName());
new Thread(futureTask).start();
System.out.println(System.currentTimeMillis()+","+Thread.currentThread().getName());
System.out.println(System.currentTimeMillis()+","+Thread.currentThread().getName()+",结果:"+futureTask.get());
}
}
运行上面的代码,输出结果:
1637910056778,main 1637910056778,main 1637910056779,Thread-0,start! 1637910061787,Thread-0,end! 1637910056778,main,结果:10
文章参考:http://www.itsoku.com/ 博主觉得这个文章的内容挺不错的,感兴趣的可以去了解一下。



