java线程(3)——详解Callable、Future和FutureTask
回顾:
接上篇博客
java线程——三种创建线程的方式,这篇博客主要介绍第三种方式Callable和Future。比较继承Thread类和实现Runnable接口,接口更加灵活,使用更广泛。但这两种方式都没有返回值,要想返回相应的数据,就要使用Callable和Future方式。
基础:
1、Callable
还是从定义开始,Callable接口有返回值,并且可以抛出异常。
/**(有返回值的任务,可能抛出异常)
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}. * @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> { V call() throws Exception;
}
2、Future
Future同样也是一个接口,主要方法如下,方法的功能比较容易理解,所以就没有写注释。主要作用:获取任务执行结果,中断任务等。
package java.util.concurrent;
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
3、FutureTask
public class FutureTask<V> implements RunnableFuture<V> {
......
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
......
}
FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future。也就是说,它既可以作为Runnable被线程执行,也可以作为Future得到Callable返回值。
使用:
方法一:Callable+Future
public class CallableAndFuture {
/**
* 实现Callable接口
*
* @author YANG
*
*/
public static class MyCallable implements Callable {
private int flag = 0;
public MyCallable(int flag) {
this.flag = flag;
}
// 重写call方法
public String call() throws Exception {
// 情况一:flag=0 返回0
if (this.flag == 0) {
return "flag = 0";
}
// 情况二:flag=1 返回looping 陷入死循环
if (this.flag == 1) {
try {
while (true) {
System.out.println("looping.");
Thread.sleep(2000);
}
// 情况三:出现异常
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
return "false";
} else {
throw new Exception("Bad flag value!");
}
}
}
public static void main(String[] args) {
// 定义3个Callable类型的任务,构造方法中制定flag的值
MyCallable task1 = new MyCallable(0);
MyCallable task2 = new MyCallable(1);
MyCallable task3 = new MyCallable(2);
// 创建一个执行任务的服务
ExecutorService es = Executors.newFixedThreadPool(3);
try {
// 提交并执行任务,任务启动时返回了一个Future对象,
// 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作
Future future1 = null;
future1 = es.submit(task1);
// 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行
System.out.println("task1: " + future1.get());
Future future2 = es.submit(task2);
// 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环
Thread.sleep(5000);
System.out.println("task2 cancel: " + future2.cancel(true));
// 测试抛出异常
Future future3 = es.submit(task3);
System.out.println("task3: " + future3.get());
} catch (Exception e) {
System.out.println(e.toString());
}
// 停止任务执行服务
es.shutdownNow();
}
}
执行结果:
方法二:Callable+FutureTask
分析两种方法不同之处就在于Future和FutureTask,其中一个是接口,一个是类。因此,只有main方法调用部分不同,上面的MyCallable类中的内容保持不变。
public static void main(String[] args) {
MyCallable task1 = new MyCallable(0);
FutureTask ft1 = new FutureTask(task1);
MyCallable task2 = new MyCallable(1);
FutureTask ft2 = new FutureTask(task2);
MyCallable task3 = new MyCallable(2);
FutureTask ft3 = new FutureTask(task3);
try {
//启动task1
new Thread(ft1, "子线程").start();
System.out.println(ft1.get());
//等待5秒后,停止task2
new Thread(ft2, "子线程").start();
Thread.sleep(5000);
System.out.println("task2 cancel:" + ft2.cancel(true));
//启动task3
new Thread(ft3, "子线程").start();
System.out.println("task3:" + ft3.get());
} catch (InterruptedException | ExecutionException e) {
System.out.println(e.toString());
}
}
其执行结果与方法一完全相同,对比这两种方式,第二种比较容易读懂,第一种相对困难些。下篇博客我们介绍Executor、ExecutorService等内容,相信之后理解起来就会很轻松了。
java线程(3)——详解Callable、Future和FutureTask的更多相关文章
- Java线程池详解(二)
一.前言 在总结了线程池的一些原理及实现细节之后,产出了一篇文章:Java线程池详解(一),后面的(一)是在本文出现之后加上的,而本文就成了(二).因为在写完第一篇关于java线程池的文章之后,越发觉 ...
- Java线程池详解
一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...
- 【java线程系列】java线程系列之java线程池详解
一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...
- Java线程池详解,看这篇就够了!
构造一个线程池为什么需要几个参数?如果避免线程池出现OOM?Runnable和Callable的区别是什么?本文将对这些问题一一解答,同时还将给出使用线程池的常见场景和代码片段. 基础知识 Execu ...
- Java 线程池详解
Executors创建线程池 Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThreads),但 ...
- Java线程池详解(一)
一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...
- Java线程学习详解
线程基础 1. 线程的生命周期 1.1 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态.它保持这个状态直到程序 start() 这个线程. 1 ...
- Java并发编程:ThreadPoolExecutor + Callable + Future(FutureTask) 探知线程的执行状况
如题 (总结要点) 使用ThreadPoolExecutor来创建线程,使用Callable + Future 来执行并探知线程执行情况: V get (long timeout, TimeUnit ...
- java 线程状态 详解
线程被创建后,有一个生命周期,下图是线程的生命周期详解. java api java.lang.Thread.State 这个枚举中给出了六种线程状态,分别是: 线程状态 导致状态发生条件 NEW(新 ...
- Java线程池 详解(图解)
来源:www.jianshu.com/p/098819be088c 拓展: 手动创建 new ThreadPoolExecutor 的使用: https://segmentfault.com/a/11 ...
随机推荐
- 封装一个方法获取url上面的参数
一.取参 ] : ); ]; ; ]., -); ]) === ]; , , b: 'fdfdfd', c: '9999' })); //a=123546&b=fdfdfd&c=9 ...
- css3 笔记
1.元字符使用: []: 全部可选项 ||:并列 |:多选一 ?: 0个或者一个 *:0个或者多个 {}: 范围 2.CSS3属性选择器: E[attr]:存在attr属性即可: E[attr=val ...
- SAP ABAP 日期,时间 相关函数
获的两个日期之间的分钟数 data min TYPE i. CALL FUNCTION 'DELTA_TIME_DAY_HOUR' EXPORTING T1 = ' T2 = ' D1 = ' D2 ...
- HDFS学习总结
1.什么是Hadoop 管理网络中跨多台计算机存储的文件系统称为分布式文件系统面临的挑战:使文件系统能容忍节点故障且不丢失任何数据不适合的特点:低时间延迟的数据访问&大量的小文件&多用 ...
- iWebShop产品功能技术优势有什么?
iwebshop基于iweb si 框架开发,在获得iweb si 技术平台支持的条件下,iwebshop可以轻松满足用户量级百万至千万级的大型电子商务网站的性能要求.站点的集群与分布式技术(分布式计 ...
- 一次 group by + order by 性能优化分析
一次 group by + order by 性能优化分析 最近通过一个日志表做排行的时候发现特别卡,最后问题得到了解决,梳理一些索引和MySQL执行过程的经验,但是最后还是有5个谜题没解开,希望大家 ...
- Oracle数据库之 PL SQL 学习笔记
1.定义基本变量: 2.引用型的变量: set serveroutput on declare pename emp.ename%type; psal emp.sal%type; begin ...
- centos搭建SVN服务
Linux VM_47_236_centos 3.10.0-514.21.1.el7.x86_64 需求:android.ios.service三个版本库 安装: yum -y install sub ...
- struts2学习
struts2是一种基于mvc模式的轻量级web框架,它本质上相当于一个servlet,在mvc设计模式中,struts2作为控制器(Controller)来建立模型与视图的数据交互,struts2采 ...
- python2.7练习小例子(九)
9)1.题目:暂停一秒输出. 程序分析:使用 time 模块的 sleep() 函数. 程序源代码: #!/usr/bin/python # -*- coding: UTF-8 ...