共计 2676 个字符,预计需要花费 7 分钟才能阅读完成。
Java 1.5 开始, 提供了 Callable
和 Future
, 通过它们可以在任务执行完毕之后得到任务执行结果.
当需要调用几个执行很慢的方法时, 可以使用多线程一起执行这几个方法, 等所有方法执行完毕后得到执行结果, 在进行别的处理.
Future 的主要方法
Future
接口主要包括 5 个方法:
get()
方法可以当任务结束后返回一个结果, 如果调用时, 工作还没有结束, 则会阻塞线程, 直到任务执行完毕.
get(long timeout,TimeUnit unit)
做多等待 timeout
的时间就会返回结果.
cancel(boolean mayInterruptIfRunning)
方法可以用来停止一个任务.
isDone()
方法判断当前方法是否完成.
isCancel()
方法判断当前方法是否取消.
Future 示例 demo
需求场景: 等早餐过程中, 包子需要 3 秒, 凉菜需要 1 秒, 普通的多线程需要四秒才能完成. 先等凉菜, 再等包子, 因为等凉菜时, 普通多线程启动 start()
方法, 执行 run()
中具体方法时, 没有返回结果, 所以如果要等有返回结果, 必须是要 1 秒结束后才知道结果.
public static void main(String[] args) throws InterruptedException, ExecutionException {long start = System.currentTimeMillis();
// 等凉菜
Callable ca1 = new Callable() {
@Override
public String call() throws Exception {
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}
return "凉菜准备完毕";
}
};
FutureTask<String> ft1 = new FutureTask<String>(ca1);
new Thread(ft1).start();
// 等包子 -- 必须要等待返回的结果,所以要调用 join 方法
Callable ca2 = new Callable() {
@Override
public Object call() throws Exception {
try {Thread.sleep(1000 * 3);
} catch (InterruptedException e) {e.printStackTrace();
}
return "包子准备完毕";
}
};
FutureTask<String> ft2 = new FutureTask<String>(ca2);
new Thread(ft2).start();
System.out.println(ft1.get());
System.out.println(ft2.get());
long end = System.currentTimeMillis();
System.out.println("准备完毕时间:" + (end - start));
}
还有一个比较典型的例子就是设置超时时间:
// 固定大小的线程池,同时只能接受 5 个任务
static ExecutorService mExecutor = Executors.newFixedThreadPool(5);
final static long timeout = 4 ;
/**
* 模拟在预定时间内获取广告信息
* @throws InterruptedException
*/
static void rederPageWithAd(final String pageTitle) throws InterruptedException{Future<String> f = mExecutor.submit(new Callable<String>() {
@Override
public String call() throws Exception {System.out.println("开始加载广告信息");
int randomTime = new Random().nextInt(5) + 1;// 限制耗时不会出现 0s,不会大于 10s
Thread.sleep(100 * 1000);
System.out.println("正常加载广告耗时:" + randomTime +"s");
return pageTitle;
}
});
String page;
try {
// 在预计时间内等待
System.out.println("预期任务执行完时间:" + timeout + "s");
//page = f.get();
page = f.get(timeout, TimeUnit.SECONDS);
} catch (ExecutionException e) {page = "出现执行异常,显示默认的广告页面";} catch (TimeoutException e) {
page = "任务执行超时,显示默认的广告页面";
f.cancel(true);// 取消没有执行完的任务,设置为 ture 说明任务能被中断,否则执行中的任务要完成
}
System.out.println("成功加载广告页面:" + page);
}
public static void main(String[] args) {
try {List<String> titleList = new ArrayList<String>();
titleList.add("体育赛事");
titleList.add("娱乐新闻");
titleList.add("实时聚焦");
titleList.add("国际咨询");
titleList.add("影视天下");
titleList.add("游戏风云");
for (String string : titleList) {rederPageWithAd(string);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();} finally{
/**
* 只有执行了 shutdown 方法,执行 isTerminated 才有效。否则 isTerminated 一直为 ture
*/
mExecutor.shutdown();
while(true){if(mExecutor.isTerminated()){System.out.println("所有任务都执行完了,关闭线程池");
break;
}
}
}
}
值得注意的是: 当主线程调用 Future
的 get
方法的时候会获取到从线程中返回的结果数据. 如果在线程的执行过程中发生了异常, get
会获取到异常的信息.
正文完