博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
FutureTask——另一种闭锁的实现
阅读量:6557 次
发布时间:2019-06-24

本文共 2870 字,大约阅读时间需要 9 分钟。

关于多线程,我们接触对多的,最基础,入门的可能就是实现Runnable接口继承Thead类,因为Java单继承的原因,通常建议是实现Runnable接口。但这种“简单”的线程会带来一个问题,写过的人都知道,不管是实现Runnable还是继承Thread类,他们都是实现public void run()方法,而这个方法可以看到是没有返回值的。但我们想执行一个线程得到它的返回值应该怎么做呢?此时FutureTask就要出场了。

首先我们还是需要定义一个线程,不同的是这个线程需要实现Callable接口。这是第一个不同的地方。

1 package futuretask; 2  3 import java.util.concurrent.Callable; 4  5 /** 6  * Created by yulinfeng on 12/17/16. 7  */ 8 public class Task implements Callable
{ 9 private String name;10 11 public Task(String name){12 this.name = name;13 }14 15 @Override16 public String call() throws Exception {17 String hello = hello(name);18 return hello;19 }20 21 public String hello(String name){22 return "hello " + name;23 }24 }

可以看到此时并不是实现run方法,而是一个叫call的方法,同时有返回值(返回值取决于所定义的泛型)。定义好这个线程过后,并不是直接将此线程的实例传入一个Thread类中执行start方法,这也是和没有返回值的线程不同的地方。

下面我们通过两种方法使用FutureTask,一个是通过线程池的方式创建线程,一个是直接创建一个线程。


通过多线程的方式创建线程:

1 package futuretask; 2  3 import countdownlatch.TaskThread; 4  5 import java.util.concurrent.*; 6  7 /** 8  * Created by yulinfeng on 12/17/16. 9  */10 public class Test {11     public static void main(String[] args){12         ExecutorService exec = Executors.newCachedThreadPool();     //创建一个线程池13         Future
hello = exec.submit(new Task("kevin")); //执行线程池的submit方法,执行callable线程,并返回一个Future对象14 try {15 System.out.println(hello.get()); //通过调用Future的get方法,获取线程的返回值16 } catch (InterruptedException e) {17 e.printStackTrace();18 } catch (ExecutionException e) {19 e.printStackTrace();20 }21 }22 }

这是第一种通过线程池创建线程的方式,通过调用线程的submit方法。如果是实现的Runnable方法,通过线程池创建线程执行的则是线程池的execute方法。一定注意调用线程返回值时使用的是Future的get方法来获取的返回值。


直接创建线程:

1 package futuretask; 2  3 import countdownlatch.TaskThread; 4  5 import java.util.concurrent.*; 6  7 /** 8  * Created by yulinfeng on 12/17/16. 9  */10 public class Test {11     public static void main(String[] args){12         FutureTask
future = new FutureTask
(new Task("kevin")); //将线程传入FuturaTask的构造方法中13 Thread thread = new Thread(future); 14 thread.start();15 try {16 System.out.println(future.get());17 } catch (InterruptedException e) {18 e.printStackTrace();19 } catch (ExecutionException e) {20 e.printStackTrace();21 }22 }23 }

在调用get方法时,一定是在执行完线程后,不然将会一直阻塞。

其实仔细观察以上两张方法,第一种是Future接口,第二种是FutureTask类。FutureTask是Future接口的实现,为什么不能将Future接口传入Thread的构造方法中呢?原因很简单。在Thread的单个参数构造方法中,只能传入Runnable类型,而Future并没有继承Runnable接口,FutureTask则同时继承了Runnable接口和Future接口。

最后,那么FutureTask应该怎么来定义呢?其实和我们上一节将的CountDownLatch一样,它也是一种闭锁的实现。Future.get取决于任务的状态,如果任务已完成,那么get会立即返回结果,否则get将阻塞直到任务进入完成状态,然后返回结果或者抛出异常。FutureTask将计算结果从执行计算的线程传递到获取这个结果的线程,而FutureTask的规范确保了这种传递过程能实现结果的安全发布。——《Java并发编程实践》

 

转载地址:http://zzhco.baihongyu.com/

你可能感兴趣的文章
Spark源码编译并在YARN上运行WordCount实例
查看>>
Spring AOP + AspectJ annotation example
查看>>
Spring VS EJB 3 的若干认识误区(转)
查看>>
React.js初探(一)
查看>>
Neo4j CQL -(17)- NULL值
查看>>
BZOJ4554: [Tjoi2016&Heoi2016]游戏 luoguP2825 loj2057
查看>>
json_encode后的中文不编码成unicode
查看>>
iOS 导航栏title显示右偏移
查看>>
修改纵断面图标注栏
查看>>
Flex创建带有空间信息的椭圆(Polygon)
查看>>
【转】参照protobuf,将json数据转换成二进制在网络中传输。
查看>>
享元模式
查看>>
Python中的str与bytes之间的转换的三种方法
查看>>
java异常常见面试问题
查看>>
课后作业5
查看>>
Centos7.1环境下搭建BugFree
查看>>
共用y轴的双图形绘制
查看>>
(错误) Eclipse使用Maven创建Web时错误
查看>>
第31讲 | 数字货币钱包服务
查看>>
P2073 送花
查看>>