如果需要多个任务同时进行的,我们用什么方式最方便呢,第一种肯定是同步进行,一个一个进行,这样子肯定最慢的,还有一种就是同时进行,即:"分而治之",使用Future<V>接口。
一、Future<V>简介
Future<V>接口是用来获取异步计算结果的,说白了就是对具体的Runnable或者Callable对象任务执行的结果进行获取(get()),取消(cancel()),判断是否完成等操作。我们看看Future接口的源码:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
方法解析:
V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCanceller() :如果任务完成前被取消,则返回true。
boolean cancel(boolean mayInterruptRunning) :如果任务还没开始,执行cancel(...)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(...)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。
通过方法分析我们也知道实际上Future提供了3种功能:
(1)能够中断执行中的任务
(2)判断任务是否执行完成
(3)获取任务执行完成后额结果。
但是我们必须明白Future只是一个接口,我们无法直接创建对象,因此就需要其实现类FutureTask登场啦。
二、实战检验
我们直接上码,看一下差距:
@Test
public void forkJoinTest() throws ExecutionException, InterruptedException {
long curTime = System.currentTimeMillis();
Future<List<String>> r1 = ThreadPoolUtils.normalPool.submit(() -> {
List<String> result = new ArrayList<>();
for (int i = 0 ; i < 1000000 ; i++) {
result.add(String.valueOf(i));
}
return result;
});
Future<List<String>> r2 = ThreadPoolUtils.normalPool.submit(() -> {
List<String> result = new ArrayList<>();
for (int i = 1000000 ; i < 2000000 ; i++) {
result.add(String.valueOf(i));
}
return result;
});
Future<List<String>> r3 = ThreadPoolUtils.normalPool.submit(() -> {
List<String> result = new ArrayList<>();
for (int i = 2000000 ; i < 3000000 ; i++) {
result.add(String.valueOf(i));
}
return result;
});
List<String> result1 = r1.get();
List<String> result2 = r2.get();
List<String> result3 = r3.get();
System.out.println(System.currentTimeMillis() - curTime);
curTime = System.currentTimeMillis();
List<String> result4 = new ArrayList<>();
for (int i = 0 ; i < 1000000 ; i++) {
result4.add(String.valueOf(i));
}
List<String> result5 = new ArrayList<>();
for (int i = 1000000 ; i < 2000000 ; i++) {
result5.add(String.valueOf(i));
}
List<String> result6 = new ArrayList<>();
for (int i = 2000000 ; i < 3000000 ; i++) {
result6.add(String.valueOf(i));
}
System.out.println(System.currentTimeMillis() - curTime);
}
执行时间如下:
由此可见, 多线程"分而治之"Future的执行效率还是很高的