1. 提出问题
计算 1 + 2 + 3 + 4 + … + 997 + 998 + 999+ 1000 = ?
2. 单线程计算
采用的单线程进行累加求和,先算1 + 2 = 3 再算 3 + 3 = 6 再算 6 + 4 = 10,依次类推直至加到1000,其中要累加999次,假设每次累加至少耗时1ms,这样计算则至少需要999ms。
2.1 代码实现
public static void test01() throws InterruptedException{
long sum = 0;
// 记录计算的开始时间
long begin = System.currentTimeMillis();
for (long i = 1; i <= 1000; i++) {
// 进行依次累加
sum = sum + i;
// 模拟耗时1ms
Thread.sleep(1);
}
// 记录计算的结束时间
long end = System.currentTimeMillis();
// 打印计算结果与耗时
System.out.println("单线程计算结果:" + sum + " 耗时:" + (end - begin) + "ms");
}
2.2 运行结果
3. 多线程计算
一个人执行任务,由于任务量大耗时较长,如果有十个人来做这批任务,它的效率理论上要提升十倍。1000个数求和,假如我有十个工人,每个工人平分工作任务各分得100个数,每个人只需要累加99次,最后汇总每位工人的计算结果就得出最终结果。
3.1 代码实现
- 任务执行者
public class ComputeCallable implements Callable<Long>
{
/**
* 计算者名称
*/
private String computeName;
/**
* 任务开始值
*/
private Long beginValue;
/**
* 任务结束值
*/
private Long endValue;
public ComputeCallable(String computeName, Long beginValue, Long endValue) {
this.computeName = computeName;
this.beginValue = beginValue;
this.endValue = endValue;
}
/**
* 计算逻辑
* @return 计算结果
*/
@Override
public Long call() throws Exception {
long result = 0;
// 记录计算的开始时间
long begin = System.currentTimeMillis();
for (long i = beginValue; i <= endValue; i++) {
// 进行依次累加
result = result + i;
// 模拟耗时1ms
Thread.sleep(1);
}
// 记录计算的结束时间
long end = System.currentTimeMillis();
// 打印计算结果与耗时
System.out.println(computeName + "计算结果:" + result + " 耗时:" + (end - begin) + "ms");
return result;
}
public String getComputeName(){
return computeName;
}
}
- 任务分配者
public static void test02() throws ExecutionException, InterruptedException{
List<FutureTask<Long>> results = new ArrayList<>(10);
// 记录计算的开始时间
long begin = System.currentTimeMillis();
// 将任务平均分配给十个工人
for (int i = 0; i < 10; i++) {
// 定义工人任务信息
String computeName = "工人" + (i + 1);
long beginValue = i * 100 + 1;
long endValue = (i + 1) * 100;
// 工人分得任务信息
ComputeCallable computeCallable = new ComputeCallable(computeName, beginValue ,endValue);
FutureTask<Long> futureTask = new FutureTask<>(computeCallable);
Thread thread = new Thread(futureTask, computeCallable.getComputeName());
// 工人执行任务
thread.start();
// 记录工人任务结果
results.add(futureTask);
}
// 汇总每个工人的计算结果
long sum = 0;
for (FutureTask<Long> result : results) {
// 汇总
sum = sum + result.get();
// 模拟耗时1ms
Thread.sleep(1);
}
long end = System.currentTimeMillis();
// 打印计算结果与耗时
System.out.println("多线程计算结果:" + sum + " 耗时:" + (end - begin) + "ms");
}
3.2 运行结果
4. FutureTask
FutureTask是一个可取消的异步任务,可以调用方法开始和取消一个任务,可以查询获取计算结果,FutureTask的状态大致可以分为三种:
- 任务未启动
- 任务执行中(可能是已经启动,只是没有开始执行)
- 任务已完成
FutureTask类实现了Future接口,Future接口提供了五个方法:
// 尝试取消任务 boolean cancel(boolean mayInterruptIfRunning)
// 任务正常结束前取消返回true boolean isCancelled()
// 任务正常结束、异常或被取消返回true boolean isDone()
// 等待任务结束获取结果 V get() throws InterruptedException, ExecutionException
// 给定时间获取结果,规定时间任务未完成抛出异常 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException