一:Future介绍和使用
- 简介:Future、Callback和Promise模式是在并发编程中经常会用到的非阻塞的模型;
a)其中Future模式可以理解为将任务提交给线程执行,其执行结果为Future(未来的结果),期间可以去做其他事情,等需要结果时,再从Future那里获取结果;其中Future模式可以理解为将任务提交给线程执行,其执行结果为Future(未来的结果),期间可以去做其他事情,等需要结果时,再从Future那里获取结果;
b)Java中还未实现带Callback的Future模式,但在Netty、Guava、Vert.x等扩展工具包中已实现,Promise模式是解决一些Callback带来的问题引入的; - Future的使用
Future一般搭配Callable来使用,一般我们使用Thread或者ExecutorService来执行,并返回执行结果Future;
Example:如下所示,在下例中启动2个线程,分别执行耗时2s的任务,最终耗时为2067ms,这就起到异步执行的效果,
private void futureInvokeResult() {
ExecutorService executor = Executors.newFixedThreadPool(3);
long mills = System.currentTimeMillis();
Callable<String> callable = () -> { Thread.sleep(2000);return "123"; };
Future<String> future1 = executor.submit(callable);
Future<String> future2 = executor.submit(callable);
Future<String> future3 = executor.submit(callable);
/**没有刻意抛出异常的情况*/
try {
System.out.println("Answer :" + future1.get(4, TimeUnit.SECONDS) +
future2.get(4, TimeUnit.SECONDS) + future3.get(4, TimeUnit.SECONDS));
} catch (Exception e) {
System.out.println(e);
}
System.out.println("总耗时:" + (System.currentTimeMillis() - mills));
executor.shutdown();
}
运行结果
Answer :123123123
总耗时:2067
- 异常控制:
上面举得例子是没有刻意抛出异常的场景,下面举出可以抛出异常的场景,这时可以捕获其异常
private void futureInvokeResult() {
ExecutorService executor = Executors.newFixedThreadPool(3);
long mills = System.currentTimeMillis();
Callable<String> callable = () -> { Thread.sleep(2000);return "123"; };
Callable<String> callable2 = () -> { throwException();return "123"; };
Future<String> future1 = executor.submit(callable);
Future<String> future2 = executor.submit(callable2);
Future<String> future3 = executor.submit(callable);
/**刻意抛出异常的情况*/
try {
System.out.println("Answer :" + future1.get(4, TimeUnit.SECONDS) +
future2.get(4, TimeUnit.SECONDS) + future3.get(4, TimeUnit.SECONDS));
} catch (InterruptedException e) {
System.out.println(e);
}catch (ExecutionException e) {
System.out.println(e);
}catch (TimeoutException e) {
System.out.println(e);
}catch (Exception e) {
System.out.println(e);
}
System.out.println("总耗时:" + (System.currentTimeMillis() - mills));
executor.shutdown();
}
private void throwException() throws TimeoutException{
throw new RuntimeException("111");
}
java.util.concurrent.ExecutionException: java.lang.RuntimeException: 111
总耗时:2057
- Future接口的方法介绍
public interface Future<V> {
//试图去cancel线程的执行,mayInterruptIfRunning为true时,可以cancel执行中的线程,
//若是线程已经执行完、、已经取消或不能取消,则返回false,未开始、不能执行返回true;
boolean cancel(boolean mayInterruptIfRunning);
//在它完成前,是否已经取消
boolean isCancelled();
//正常结束、异常终止或取消,返回true
boolean isDone();
//尝试去获取结果,并等待执行完成
V get() throws InterruptedException, ExecutionException;
//尝试去获取结果,并等待执行完成,超时则异常
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
二:Future的缺点和改进
- 缺点:
a)Future.get必须要阻塞的进行结果获取,或者是使用isDone()轮询进行结果查询;
b)Future功能比较单一,仅仅提供了针对一个线程操作的,没有提供一系列方便的操作,比如上面例子中还需要单点的去执行,不能针对List去执行; - Java8中引入了CompletableFuture,提供了一系列的优化;