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 ...
随机推荐
- 技巧:Vimdiff 使用
技巧:Vimdiff 使用 各种 IDE 大行其道的同时,传统的命令行工具以其短小精悍,随手可得的特点仍有很大的生存空间,这篇短文介绍了一个文本比较和合并的小工具:vimdiff.希望能对在 Unix ...
- php第五节(字符串函数和时间、日期函数)
<?php //查找字符串函数 // strpos() 查找字符第一次出现的位置 重点区分大小写 //stripos — 查找字符串首次出现的位置(不区分大小写) //strrpos — 计算指 ...
- 洛谷P1731 [NOI1999]生日蛋糕(爆搜)
题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱 ...
- 洛谷P3871 [TJOI2010]中位数(splay)
题目描述 给定一个由N个元素组成的整数序列,现在有两种操作: 1 add a 在该序列的最后添加一个整数a,组成长度为N + 1的整数序列 2 mid 输出当前序列的中位数 中位数是指将一个序列按照从 ...
- ABAP术语-Fiscal Year
Fiscal Year 原文:http://www.cnblogs.com/qiangsheng/archive/2008/02/02/1062109.html Generally a period ...
- MySQL 字符串函数:字符串截取
1.left(name,4)截取左边的4个字符 列: ,) 年 结果:2018 2.right(name,2)截取右边的2个字符 ,) 月份 结果:09 3.SUBSTRING(name,5,3) 截 ...
- 第一次学习tornado小练习
内容 这次是python的一个web框架,tornado,这个web框架在python的几个web框架中一个比较简单的web框架,刚开始接触python的时候就知道python有两个比较常用的web框 ...
- ruby Dir类
类方法 1. Dir[pat] Dir::glob( pat) 返回一个数组,包含与指定的通配符模式 pat 匹配的文件名: * - 匹配包含 null 字符串的任意字符串 ** - 递归地匹配 ...
- Teen Readers【青少年读者】
Teen Readers Teens and younger children are reading a lot less for fun, according to a Common Sense ...
- centos 安装java1.8
https://www.cnblogs.com/xuliangxing/p/7066913.html