FutureTask——另一种闭锁的实现
关于多线程,我们接触对多的,最基础,入门的可能就是实现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——另一种闭锁的实现的更多相关文章
- 并发编程-Future+callable+FutureTask 闭锁机制
项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现. FutureTask ...
- 深入浅出 Java Concurrency (10): 锁机制 part 5 闭锁 (CountDownLatch)
此小节介绍几个与锁有关的有用工具. 闭锁(Latch) 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻 ...
- 深入浅出 Java Concurrency (10): 锁机制 part 5 闭锁 (CountDownLatch)[转]
此小节介绍几个与锁有关的有用工具. 闭锁(Latch) 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻 ...
- jdk1.8 J.U.C之FutureTask实现机制分析
我画了一张关于FutureTask的类图,主要包括FutureTask的几个重要的函数和字段,还有它和父类的关系. 根据上面图我们可以清晰的看出FutureTask的继承关系.FutureTask继承 ...
- CountDownLatch——闭锁的实现之一
CountDownLatch实际上是一种闭锁实现.闭锁:是一种同步工具类,可以延迟线程的进度知道其到达终止状态--<Java并发编程实战>.这个怎么解释呢?简单来说,就是有1个线程需要等待 ...
- FutureTask理解
一.概述 FutureTask包装器是一种非常便利的机制,同时实现了Future和Runnable接口. 类图如下: FutureTask是一种可以取消的异步的计算任务.它的计算是通过Callable ...
- Callable,Future和FutureTask详解
1.Callable和Runnable 看Callable接口: public interface Callable<V> { /** * Computes a result, or th ...
- 【并发编程】【JDK源码】J.U.C--组件FutureTask、ForkJoin、BlockingQueue
原文:慕课网实战·高并发探索(十三):并发容器J.U.C -- 组件FutureTask.ForkJoin.BlockingQueue FutureTask FutureTask是J.U.C中的类,是 ...
- 并发编程—— FutureTask 源码分析
1. 前言 当我们在 Java 中使用异步编程的时候,大部分时候,我们都会使用 Future,并且使用线程池的 submit 方法提交一个 Callable 对象.然后调用 Future 的 get ...
随机推荐
- VSCode里的一些有用的插件
1.EaseServer 作用:开启本地 http server,然后在browser里打开html: 在调试页面的时候,打开页面比较方便,不需要先开启server,再打开html 2.Debugge ...
- 老李分享:持续集成学好jenkins之解答疑问
老李分享:持续集成学好jenkins之解答疑问 poptest(www.poptest.cn)在培训的过程中使用jenkins搭建持续集成环境,让学员真正交流持续集成到底是什么,怎么去做的. Je ...
- poptest老李谈分布式与集群 2
集群分类 Linux集群主要分成三大类( 高可用集群, 负载均衡集群,科学计算集群) 高可用集群( High Availability Cluster)负载均衡集群(Load Balance Clus ...
- Oracle DBA管理包脚本系列(二)
该系列脚本结合日常工作,方便DBA做数据管理.迁移.同步等功能,以下为该系列的脚本,按照功能划分不同的包.功能有如下: 1)数据库对象管理(添加.修改.删除.禁用/启用.编译.去重复.闪回.文件读写. ...
- PHP童鞋改JAVA代码怎么处理
用线上升级平台代码练手,学习JAVA.飞哥建议我们自己从头再搭建一套,提高会大.我自己作为一个JAVA出身的人,用了几天时间学会PHP的经验来看.最好,先在原来代码基础上改些东西.熟悉了基本语法之后再 ...
- ls命令的20个实用范例
contents ls -l -h -lhS -l --block-size=M -a -d */ -g -G -n --color=never -i -p -r -R -t ls ~ ls --ve ...
- 在ASP.NET MVC4中配置Castle
---恢复内容开始--- Castle是针对.NET平台的一个非常优秀的开源项目,重点是开源的哦.它在NHibernate的基础上进一步封装,其原理基本与NHibernate相同,但它较好地解决NHi ...
- Xcode上传代码到github
1.下载GitHub的Mac客户端 2.在Finder->下载,找到双击安装 3.打开Github Desktop软件, 需要进行登录, 登录的用户名密码就是github的用户信息,(如果没有去 ...
- Linux--谈父子进程执行过程
fork函数用于从已存在进程中创建一个新进程,新进程成为子进程,原进程成为父进程.这两个进程分别返回他们各自的返回值, 其中父进程的返回值是子进程的进程号,子进程则返回0,因此返回值大于0标识父进程, ...
- XStream的使用
一:功能 可以将JavaBean转换(序列化)成XMl 二:依赖jar包 xstream.jar xpp3_min.jar(xml pull parser)xml解析器 三:使用步骤 XStream ...