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

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

 package futuretask;

 import java.util.concurrent.Callable;

 /**
* Created by yulinfeng on 12/17/16.
*/
public class Task implements Callable<String> {
private String name; public Task(String name){
this.name = name;
} @Override
public String call() throws Exception {
String hello = hello(name);
return hello;
} public String hello(String name){
return "hello " + name;
}
}

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

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


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

 package futuretask;

 import countdownlatch.TaskThread;

 import java.util.concurrent.*;

 /**
* Created by yulinfeng on 12/17/16.
*/
public class Test {
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool(); //创建一个线程池
Future<String> hello = exec.submit(new Task("kevin")); //执行线程池的submit方法,执行callable线程,并返回一个Future对象
try {
System.out.println(hello.get()); //通过调用Future的get方法,获取线程的返回值
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}

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


直接创建线程:

 package futuretask;

 import countdownlatch.TaskThread;

 import java.util.concurrent.*;

 /**
* Created by yulinfeng on 12/17/16.
*/
public class Test {
public static void main(String[] args){
FutureTask<String> future = new FutureTask<String>(new Task("kevin")); //将线程传入FuturaTask的构造方法中
Thread thread = new Thread(future);
thread.start();
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}

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

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

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

FutureTask——另一种闭锁的实现的更多相关文章

  1. 并发编程-Future+callable+FutureTask 闭锁机制

    项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现. FutureTask ...

  2. 深入浅出 Java Concurrency (10): 锁机制 part 5 闭锁 (CountDownLatch)

    此小节介绍几个与锁有关的有用工具. 闭锁(Latch) 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻 ...

  3. 深入浅出 Java Concurrency (10): 锁机制 part 5 闭锁 (CountDownLatch)[转]

    此小节介绍几个与锁有关的有用工具. 闭锁(Latch) 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻 ...

  4. jdk1.8 J.U.C之FutureTask实现机制分析

    我画了一张关于FutureTask的类图,主要包括FutureTask的几个重要的函数和字段,还有它和父类的关系. 根据上面图我们可以清晰的看出FutureTask的继承关系.FutureTask继承 ...

  5. CountDownLatch——闭锁的实现之一

    CountDownLatch实际上是一种闭锁实现.闭锁:是一种同步工具类,可以延迟线程的进度知道其到达终止状态--<Java并发编程实战>.这个怎么解释呢?简单来说,就是有1个线程需要等待 ...

  6. FutureTask理解

    一.概述 FutureTask包装器是一种非常便利的机制,同时实现了Future和Runnable接口. 类图如下: FutureTask是一种可以取消的异步的计算任务.它的计算是通过Callable ...

  7. Callable,Future和FutureTask详解

    1.Callable和Runnable 看Callable接口: public interface Callable<V> { /** * Computes a result, or th ...

  8. 【并发编程】【JDK源码】J.U.C--组件FutureTask、ForkJoin、BlockingQueue

    原文:慕课网实战·高并发探索(十三):并发容器J.U.C -- 组件FutureTask.ForkJoin.BlockingQueue FutureTask FutureTask是J.U.C中的类,是 ...

  9. 并发编程—— FutureTask 源码分析

    1. 前言 当我们在 Java 中使用异步编程的时候,大部分时候,我们都会使用 Future,并且使用线程池的 submit 方法提交一个 Callable 对象.然后调用 Future 的 get ...

随机推荐

  1. Memcache存储机制与指令汇总

    1.memcache基本简介 memcached是高性能的分布式内存缓存服务器.一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度.提高可扩展性. Memcach ...

  2. Quartz.NET总结(六)了解Jobs 和 Triggers

    前面讲了一些Quartz.net 的一些东西, http://www.cnblogs.com/zhangweizhong/category/771057.html 但是发现有一些基础的东西,没有说到. ...

  3. 【Hexo】Hexo+Github构建个人博客 (三):添加皮肤主题

    一.选择主题 选择你自己喜欢的主题 参考: 1.Hexo官网主题 2.知乎:有哪些好看的 Hexo 主题? 二.配置主题 1.我选择了hexo-theme-yilia这个主题,简洁大方,功能齐全: 这 ...

  4. Laravel查询构造器的使用方法整理

    1.结果集 1.1从一张表获取所有行,get方法获取所有行 $users = DB::table('users')->get(); 获取列的值 foreach ($users as $user) ...

  5. 【原创】Octovis在Ubuntu16.04下运行出现core dump的解决方案

    本人SLAM研究新手,使用系统为Ubuntu16.04.本文原址:http://www.cnblogs.com/hitlrk/p/6667253.html 在学习SLAM的过程中,使用Octomap进 ...

  6. 如何通过 HSB 颜色模式构建夜间模式

    中国睡眠研究会发布的<2017 年中国青年睡眠现状报告>显示,大约 90% 的人在睡前离不开电子产品. 不知道大家有没有感觉到普通的亮色界面会让我们在夜间使用的时侯感到刺眼,长时间使用会感 ...

  7. Java 中的 String 类常用方法

    字符串广泛应用在Java编程中,在Java中字符串属于对象,String 类提供了许多用来处理字符串的方法,例如,获取字符串长度.对字符串进行截取.将字符串转换为大写或小写.字符串分割等. Strin ...

  8. 【linux 爱好者群】程序猿的那些聊天记录

    分享&&交流&&开放 you should get it 声明:好吧,我们的群只有5个人,但是有句话不是说的很对吗,一个项目最理想的不就是5个人么.我是写文本那个. 下 ...

  9. GPIO的配置过程

    今天看到一篇很好的博文,,看这里:http://www.cnblogs.com/crazyxu/archive/2011/10/14/2212337.html 下面总结一下,加深一下理解. 要使用GP ...

  10. JQuery事件与动画总结

    1.加载DOM 1.1.window事件 window.onload=function(){}.... 时机:其他资源都加载完毕后,再执行 $(function(){}) ……:只是等待标签完毕,即可 ...