A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready
在并发编程的时候一般使用runable,然后把任务扔给线程池,这种情况不需要发返回线程执行的结果,所以run的返回值是void类型.
如果是多线程协作程序,需要线程返回结果,就需要调用callable接口了.
callable用法和runable用法一样,只不过调用的是call方法,该方法返回一个泛型的返回值类型,可以任意指定.
线程属于异步计算模型,所以不能直接从别的线程中得到函数的返回值.Future可以监控目标线程的调用call的情况,当你调用Futrue的get方法以获的结果的时候,当前线程开始阻塞,直到call方法返回结果.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* Created by xixuebin on 05/01/2018.
*/
public class FutureTest {
public static class Task implements Runnable{
public void run() {
System.out.println("ah");
}
}
public static class Task2 implements Callable{
@Override
public String call() throws Exception {
System.out.println("ah2");
return "hello world";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
List<Future<String>> results = new ArrayList<Future<String>>();
for (int i = 0; i < 100; i++) {
es.submit(new Task());
results.add(es.submit(new Task2()));
}
for (Future<String> future : results){
System.out.println("---"+ future.get());
}
}
}
Future模式的JDK内置实现
由于Future是非常常用的多线程设计模式,因此在JDK中内置了Future模式的实现。这些类在java.util.concurrent包里面。其中最为重要的是FutureTask类,它实现了Runnable接口,作为单独的线程运行。在其run()方法中,通过Sync内部类调用Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()方法时,将返回Callable接口的返回对象。同样,针对上述的实例,如果使用JDK自带的实现,则需要作如下调整。
首先,Data接口和FutureData就不需要了,JDK帮我们实现了。
其次,RealData改为这样:
import java.util.concurrent.Callable;
public class RealData implements Callable<String> {
protected String data;
public RealData(String data) {
this.data = data;
}
@Override
public String call() throws Exception {
//利用sleep方法来表示真是业务是非常缓慢的
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class Application {
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask =
new FutureTask<String>(new RealData("name"));
ExecutorService executor =
Executors.newFixedThreadPool(1); //使用线程池
//执行FutureTask,相当于上例中的client.request("name")发送请求
executor.submit(futureTask);
//这里可以用一个sleep代替对其他业务逻辑的处理
//在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间
Thread.sleep(2000);
//使用真实数据
//如果call()没有执行完成依然会等待
System.out.println("数据=" + futureTask.get());
}
}
Future设置线程执行时间
在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。
Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果,也可以设置任务执行的超时时间。这个设置超时的方法就是实现Java程序执行超时的关键。
ExecutorService executor = Executors.newSingleThreadExecutor();
FutureTask<String> future =
new FutureTask<String>(new Callable<String>() {//使用Callable接口作为构造参数
public String call() {
//真正的任务在这里执行,这里的返回值类型为String,可以为任意类型
}});
executor.execute(future);
//在这里可以做别的任何事情
try {
result = future.get(5000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果
} catch (InterruptedException e) {
futureTask.cancel(true);
} catch (ExecutionException e) {
futureTask.cancel(true);
} catch (TimeoutException e) {
futureTask.cancel(true);
} finally {
executor.shutdown();
}