Java并发36:Callable+Future系列--FutureTask学习笔记
本章主要学习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<Integer> callable = new Callable<Integer>() { @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<Integer> futureTask = new FutureTask<Integer>(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<Integer> futureTask1 = new FutureTask<Integer>(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<AtomicInteger> futureTask2 = new FutureTask<AtomicInteger>(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<AtomicInteger> futureTask3 = new FutureTask<AtomicInteger>(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