回顾:

接上篇博客

java线程——三种创建线程的方式,这篇博客主要介绍第三种方式Callable和Future。比较继承Thread类和实现Runnable接口,接口更加灵活,使用更广泛。但这两种方式都没有返回值,要想返回相应的数据,就要使用Callable和Future方式。

基础:

1、Callable

还是从定义开始,Callable接口有返回值,并且可以抛出异常。


  1. /**(有返回值的任务,可能抛出异常)
  2. * A task that returns a result and may throw an exception.
  3. * Implementors define a single method with no arguments called
  4. * {@code call}.
  5. * @see Executor
  6. * @since 1.5
  7. * @author Doug Lea
  8. * @param <V> the result type of method {@code call}
  9. */
  10. @FunctionalInterface
  11. public interface Callable<V> {
  12. V call() throws Exception;
  13. }


2、Future

Future同样也是一个接口,主要方法如下,方法的功能比较容易理解,所以就没有写注释。主要作用:获取任务执行结果,中断任务等。


  1. package java.util.concurrent;
  2. public interface Future<V> {
  3. boolean cancel(boolean mayInterruptIfRunning);
  4. boolean isCancelled();
  5. boolean isDone();
  6. V get() throws InterruptedException, ExecutionException;
  7. V get(long timeout, TimeUnit unit)
  8. throws InterruptedException, ExecutionException, TimeoutException;
  9. }

3、FutureTask


  1. public class FutureTask<V> implements RunnableFuture<V> {
  2. ......
  3. }
  4. public interface RunnableFuture<V> extends Runnable, Future<V> {
  5. ......
  6. }

FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future。也就是说,它既可以作为Runnable被线程执行,也可以作为Future得到Callable返回值。

使用:

方法一:Callable+Future


  1. public class CallableAndFuture {
  2. /**
  3. * 实现Callable接口
  4. *
  5. * @author YANG
  6. *
  7. */
  8. public static class MyCallable implements Callable {
  9. private int flag = 0;
  10. public MyCallable(int flag) {
  11. this.flag = flag;
  12. }
  13. // 重写call方法
  14. public String call() throws Exception {
  15. // 情况一:flag=0 返回0
  16. if (this.flag == 0) {
  17. return "flag = 0";
  18. }
  19. // 情况二:flag=1 返回looping 陷入死循环
  20. if (this.flag == 1) {
  21. try {
  22. while (true) {
  23. System.out.println("looping.");
  24. Thread.sleep(2000);
  25. }
  26. // 情况三:出现异常
  27. } catch (InterruptedException e) {
  28. System.out.println("Interrupted");
  29. }
  30. return "false";
  31. } else {
  32. throw new Exception("Bad flag value!");
  33. }
  34. }
  35. }
  36. public static void main(String[] args) {
  37. // 定义3个Callable类型的任务,构造方法中制定flag的值
  38. MyCallable task1 = new MyCallable(0);
  39. MyCallable task2 = new MyCallable(1);
  40. MyCallable task3 = new MyCallable(2);
  41. // 创建一个执行任务的服务
  42. ExecutorService es = Executors.newFixedThreadPool(3);
  43. try {
  44. // 提交并执行任务,任务启动时返回了一个Future对象,
  45. // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作
  46. Future future1 = null;
  47. future1 = es.submit(task1);
  48. // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行
  49. System.out.println("task1: " + future1.get());
  50. Future future2 = es.submit(task2);
  51. // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环
  52. Thread.sleep(5000);
  53. System.out.println("task2 cancel: " + future2.cancel(true));
  54. // 测试抛出异常
  55. Future future3 = es.submit(task3);
  56. System.out.println("task3: " + future3.get());
  57. } catch (Exception e) {
  58. System.out.println(e.toString());
  59. }
  60. // 停止任务执行服务
  61. es.shutdownNow();
  62. }
  63. }

执行结果:

方法二:Callable+FutureTask

分析两种方法不同之处就在于Future和FutureTask,其中一个是接口,一个是类。因此,只有main方法调用部分不同,上面的MyCallable类中的内容保持不变。


  1. public static void main(String[] args) {
  2. MyCallable task1 = new MyCallable(0);
  3. FutureTask ft1 = new FutureTask(task1);
  4. MyCallable task2 = new MyCallable(1);
  5. FutureTask ft2 = new FutureTask(task2);
  6. MyCallable task3 = new MyCallable(2);
  7. FutureTask ft3 = new FutureTask(task3);
  8. try {
  9. //启动task1
  10. new Thread(ft1, "子线程").start();
  11. System.out.println(ft1.get());
  12. //等待5秒后,停止task2
  13. new Thread(ft2, "子线程").start();
  14. Thread.sleep(5000);
  15. System.out.println("task2 cancel:" + ft2.cancel(true));
  16. //启动task3
  17. new Thread(ft3, "子线程").start();
  18. System.out.println("task3:" + ft3.get());
  19. } catch (InterruptedException | ExecutionException e) {
  20. System.out.println(e.toString());
  21. }
  22. }

其执行结果与方法一完全相同,对比这两种方式,第二种比较容易读懂,第一种相对困难些。下篇博客我们介绍Executor、ExecutorService等内容,相信之后理解起来就会很轻松了。

java线程——详解Callable、Future和FutureTask的更多相关文章

  1. Java线程池(Callable+Future模式)

    转: Java线程池(Callable+Future模式) Java线程池(Callable+Future模式) Java通过Executors提供四种线程池 1)newCachedThreadPoo ...

  2. java线程详解

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  3. Java线程详解----借鉴

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  4. Java线程池 / Executor / Callable / Future

    为什么需要线程池?   每次都要new一个thread,开销大,性能差:不能统一管理:功能少(没有定时执行.中断等).   使用线程池的好处是,可重用,可管理.   Executor     4种线程 ...

  5. 【转】Java线程详解

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  6. java线程详解(三)

    java线程间通信 首先看一段代码 class Res { String name; String sex; } class Input implements Runnable { private R ...

  7. 并发编程 || Java线程详解

    通用线程模型 在很多研发当中,实际应用是基于一个理论再进行优化的.所以,在了解JVM规范中的Java线程的生命周期之前,我们可以先了解通用的线程生命周期,这有助于我们后续对JVM线程生命周期的理解. ...

  8. java线程详解(二)

    1,线程安全 先看上一节程序,我们稍微改动一下: //线程安全演示 //火车站有16张票,需要从四个窗口卖出,如果按照上面的多线程实现,程序如下 class Ticket implements Run ...

  9. java线程详解(一)

    1,相关概念简介 (1)进程:是一个正在执行的程序.每一个进程执行都有一个执行的顺序,该顺序就是一个执行路径,或者叫一个控制单元.用于分配空间. (2)线程:就是进程中一个独立的控制单元,线程在控制着 ...

随机推荐

  1. 如何批量ping地址查看网络是否畅通

    测试环境搬迁后,需要批量去ping所有机器的IP,看网络是否畅通 测试思路: [weblogic@pays03pre_BankVerify luyantest]$ ping -c 1 172.29.1 ...

  2. 【Linux下禁用rm命令之建立回收站】

    第一步 创建回收站目录 # 根据自己的习惯,找个位置创建一个用作回收文件的目录 # 我们这里将在root目录下面创建一个名为".trash"的隐藏文件 [root@fedora ~ ...

  3. Reference Counting GC (Part two :Partial Mark & Sweep)

    目录 部分标记清除算法 前提 dec_ref_cnt()函数 new_obj()函数 scan_hatch_queue()函数 paint_gray()函数 scan_gray()函数 collect ...

  4. ls---显示文件目录各项信息

    ls命令用来显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. 语法 ls(选项)(参数) 选项 -a:显示所有档案及目录(ls内定将档案名 ...

  5. mysql的my.cnf文件详解

    一.缘由 最近要接手数据库的维护工作,公司首选MySQL.对于MySQL的理解,我认为很多性能优化工作.主从主主复制都是在调整参数,来适应不同时期不同数量级的数据. 故,理解透彻my.cnf里的参数是 ...

  6. CodeForcesGym 100502D Dice Game

    Dice Game Time Limit: 1000ms Memory Limit: 524288KB This problem will be judged on CodeForcesGym. Or ...

  7. I帧、P帧和B帧的特点

    I帧:帧内编码帧 I帧特点: 1.它是一个全帧压缩编码帧.它将全帧图像信息进行JPEG压缩编码及传输; 2.解码时仅用I帧的数据就可重构完整图像; 3.I帧描写叙述了图像背景和运动主体的详情; 4.I ...

  8. vim 技巧之用宏命令批量处理文件

    今天遇到了一种情况,就是我需要同时修改34个文件中的某些字符串的内容,如果一个个打开需改的话,那也太麻烦了.后来就想着能不能通过vim的宏命令来修改呢?现在就总结下关于宏在文件列表中的应用1.首先,我 ...

  9. Ajax缓存原理

    一.什么是Ajax缓存原理? Ajax在发送的数据成功后,会把请求的URL和返回的响应结果保存在缓存内,当下一次调用Ajax发送相同的请求时,它会直接从缓存中把数据取出来,这是为了提高页面的响应速度和 ...

  10. js中常用的对象—String的属性和方法

    今天说一下,js中常用的内置对象——String对象它有以下几个常用的属性:lengthprototype 有以下几个常用的方法:parseInt()转换为数字parseFloat()转换为数字,支持 ...