Future模式
Future模式是多线程开发中的一种常见的设计模式,核心思想异步调用,让串行化的问题变得并行处理节省时间。当程序执行一个任务时,这个任务可能执行的很慢,它不可能立即返回结果,但可以返回一个契约,因此我们可以在该任务执行的时候,再去执行其它任务,最终用该契约获取结果。
举个例子:在网上买了一部手机,手机三天后才会到货,但会马上产生一个订单,这个订单就是上述所提到的契约,然后我们不用一直干等手机的到来,完全可以去忙别的事,当快递到来的时候,订单核对一下,然后就获得了最终结果。
JDK中的Future模式
Future接口类似于之前的契约,根据Future对象调用get方法最终获取到结果。FutureTask接口实现Callable接口对象到Runnable接口对象的过渡,其内部有一个Sync内部类,里面做一些实质性的工作,但最终会交由Callable接口完成,Callable接口的call方法返回最终结果。
简单使用
- get方法
package com.github.excelent01;
import java.util.concurrent.*;
/**
* @auther plg
* @date 2019/5/17 16:54
*/
public class TestFuture {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
Future<Integer> future = service.submit(()->{
TimeUnit.SECONDS.sleep(10); // 模拟延时
return 10;
});
//==============================
System.out.println("do other works.");
//==============================
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
service.shutdown();
}
}
Future的get()方法会阻塞调用它的线程,直至取得返回结果,该方法会抛出一个中断异常,这个中断异常是中断调用get方法的线程时所引起的。与执行call方法的线程无关。其中get方法有一个重载即等待一定的时间,超出时间后就不等了,会响应一个异常,然后退出。
其它方法
- boolean cancel(boolean mayInterruptIfRunning);
取消任务,取消成功返回true,否则返回false。参数表示是否运行取消任务,正在执行且没有执行完的任务,都可以取消掉,若任务已经执行完毕,则不可以取消掉。任务没执行前不论参数是true或者false最终都返回true。 - boolean isCancelled();
判断任务是否已经取消 - boolean isDone();
判断任务是否已经完成
通过煮茶过程练习使用Future模式
因为烧水要花费15min,因此没有必要白白干等,浪费时间,在这个时间段内,可以去完成准备茶具的一些工作,等茶具准备好之后,就静等水烧开了。因此这是一个典型的依靠Future模式来解决的问题。
代码实现:
package Future;
import java.util.Scanner;
import java.util.concurrent.*;
/**
* @auther plg
* @date 2019/5/17 17:54
*/
public class TeaTest2 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
BoilWater boilWater = new BoilWater();
FutureTask<String> futureTask1 = new FutureTask<>(boilWater);
ReadyTeaSet readyTeaSet = new ReadyTeaSet(futureTask1);
FutureTask<String> futureTask2 = new FutureTask<>(readyTeaSet);
new Thread(futureTask1).start();
Thread.sleep(2000);
new Thread(futureTask2).start();
System.out.println(futureTask2.get());
}
}
// T1 线程
class BoilWater implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("T1: 洗水壶");
Thread.sleep(1000);
System.out.println("T1: 烧水");
Thread.sleep(10000);
return "T1: 水烧开了。";
}
}
// T2 线程ReadyTeaSet
class ReadyTeaSet implements Callable<String>{
private FutureTask<String> futureTask = null;
public ReadyTeaSet(FutureTask<String> futureTask) {
this.futureTask = futureTask;
}
@Override
public String call() throws Exception {
System.out.println("T2: 洗水杯");
Thread.sleep(1000);
System.out.println("T2: 洗茶壶");
Thread.sleep(2000);
System.out.println("T2: 取茶叶");
Thread.sleep(1000);
System.out.println("T2: 等着水烧开。");
System.out.println(futureTask.get());
return "一壶好茶.";
}
}