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
    

在这里插入图片描述

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐