Java并发36:Callable+Future系列--FutureTask学习笔记

[超级链接:Java并发学习系列-绪论]


本章主要学习FutureTask接口。

1.FutureTask概述

FutureTask类表示一个可以取消的异步计算任务。

这个类提供了对Future接口的简单实现,提供了一些方法:开启计算、取消计算、查询计算是否完成和查询计算结果

只有计算完成时,才可以通过get()方法获取计算结果;如果计算没有完成,则get()方法会一致在阻塞。

一个FutureTask类可以被用于包装Callable接口或者Runnable接口的实现对象。

因为FutureTask类实现了Runnable接口,所以它可以被提交(submit)给一个Executor接口进行执行。

除了作为一个单独的类使用之外,此类还提供了protected的方法,当创建定制的任务类时,这些方法可能十分有用。

2.FutureTask的方法说明

FutureTask类的方法与Future接口类似:

1.isDone():任务是否完成

2.isCancelled():任务是否取消了

3.cancel(mayInterruptIfRunning):

取消任务:

  • mayInterruptIfRunning = true:如果任务在运行,则即使中断任务,也要取消任务。
  • mayInterruptIfRunning = false:如果任务在运行,则等待任务运行完毕,再取消任务。

4.get():

阻塞的的获取计算结果,直到发生以下三种情况之一:

  • 获取了计算结果,返回结果。
  • 当前线程被中断被中断,抛出InterruptedException异常
  • 计算出错,则抛出ExecutionException异常

5.get(timeout,TimeUnit):

限定时间内,阻塞的的获取计算结果,直到发生以下四种情况之一:

  • 获取了计算结果,则返回结果。
  • 当前线程被中断被中断,则抛出InterruptedException异常
  • 计算出错,则抛出ExecutionException异常
  • 等待时间超时,则抛出TimeoutException异常

3.FutureTask与Future的对比

相似之处:

  • 都可以与Callable接口结合使用,用于存储异步计算的结果。
  • 方法类似。

区别之处:

  • FutureTask类可以包装Runnable和Callable。
  • FutureTask类实现了Runnable接口,弥补了Thread的不足。

4.实例练习

练习目的:

  • 熟悉FutureTask类的方法使用。
  • 理解包装的概念。
  • 理解FutureTask类Runnable接口提供的便利。

练习内容:

  • 以下面多种方式实现随机数的获取:
  • 方式1:Future + Callable + ExecutorService
  • 方式2:FutureTask + Callable + ExecutorService
  • 方式3:FutureTask + Callable + Thread
  • 方式4:FutureTask + Runnable + ExecutorService
  • 方式5:FutureTask + Runnable + Thread

实例代码:

/*
- 五种方式对比
- FutureTask与Future的方法类似,不再赘述
 */
//定义一个线程池
ExecutorService service = Executors.newCachedThreadPool();
//定义一个Callable对象
Callable callable = new Callable() {
    @Override
    public Integer call() throws Exception {
        Thread.sleep(2000);
        return RandomUtils.nextInt(100, 200);
    }
};

//方式1:通过Future + Callable + ExecutorService获取值
Future future = service.submit(callable);
//获取结果
try {
    System.out.println("方式1:Future + Callable + ExecutorService 计算结果:" + future.get());
} catch (InterruptedException e) {
    //e.printStackTrace();
    System.out.println("Future 被中断");
} catch (ExecutionException e) {
    //e.printStackTrace();
    System.out.println("Future 执行出错");
}

System.out.println();
//方式2:通过FutureTask + Callable + ExecutorService取值 -- FutureTask包装Callable接口
//定义一个FutureTask对象
FutureTask futureTask = new FutureTask(callable);
//提交一个FutureTask
service.submit(futureTask);
//获取结果
try {
    System.out.println("方式2:FutureTask包装Callable接口 + ExecutorService 计算结果:" + futureTask.get());
} catch (InterruptedException e) {
    //e.printStackTrace();
    System.out.println("FutureTask(ExecutorService) 被中断");
} catch (ExecutionException e) {
    //e.printStackTrace();
    System.out.println("FutureTask(ExecutorService) 执行出错");
}

System.out.println();
//方式3:通过FutureTask + Callable + Thread取值 -- FutureTask包装Callable接口
//定义一个FutureTask对象
FutureTask futureTask1 = new FutureTask(callable);
//裸线程方式
new Thread(futureTask1).start();
//获取结果
try {
    System.out.println("方式3:FutureTask包装Callable接口 + Thread 的计算结果:" + futureTask1.get());
} catch (InterruptedException e) {
    //e.printStackTrace();
    System.out.println("FutureTask(Thread) 被中断");
} catch (ExecutionException e) {
    //e.printStackTrace();
    System.out.println("FutureTask(Thread) 执行出错");
}

//方法4和5
//定义一个结果对象
AtomicInteger result = new AtomicInteger(0);
//定义一个Runnable对象
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result.compareAndSet(0, RandomUtils.nextInt(100, 200));
    }
};


System.out.println();
//方式4:通过FutureTask + Runnable + ExecutorService 取值 -- FutureTask包装Runnable接口
//定义一个FutureTask对象
FutureTask futureTask2 = new FutureTask(runnable, result);
//第二种 ExecutorService
service.submit(futureTask2);
//循环等待结果
while (result.get() == 0) ;
//输出结果
System.out.println("方式4:FutureTask包装Runnable接口 + ExecutorService 的计算结果:" + result.get());

System.out.println();
//方式5:通过FutureTask + Runnable + Thread 取值 -- FutureTask包装Runnable接口
//清除result的值
result.set(0);
//定义一个FutureTask对象
FutureTask futureTask3 = new FutureTask(runnable, result);
//第一种 裸线程
new Thread(futureTask3).start();
//循环等待结果
while (result.get() == 0) ;
//输出结果
System.out.println("方式5:FutureTask包装Runnable接口 + Thread  的计算结果:" + result.get());

//关闭线程池
service.shutdown();

运行结果:

方式1:Future + Callable + ExecutorService 计算结果:186

方式2:FutureTask包装Callable接口 + ExecutorService 计算结果:101

方式3:FutureTask包装Callable接口 + Thread 的计算结果:130

方式4:FutureTask包装Runnable接口 + ExecutorService 的计算结果:101

方式5:FutureTask包装Runnable接口 + Thread  的计算结果:113

你可能感兴趣的:(Java并发,Java并发学习实例)