一、使用步骤

虽然Runnable接口实现多线程比继承Thread类实现多线程方法要好,但是Runnable接口里的run方法并不能返回操作结果。为了解决这样的矛盾,java提供了Callable接口。

创建并启动有返回值的线程的步骤如下:

  1. 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值,再创建Callable实现类的实例
  2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值
  3. 使用FutureTask对象作为Thread对象的target创建并启动新线程
  4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

二、源码

这个接口的源码如下:

@FunctionalInterface
public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;
}

call方法执行完线程的主体功能之后(类似于Runnable的run方法)会返回值,而返回值类型由Callable接口上的泛型决定。

以下是一个定义使用Callable接口的例子,定义了一个线程主体类:

class MyThread implements Callable<String>{private int ticket=10;@Overridepublic String call() throws Exception{for(int i=0;i<200;i++){if(this.ticket>0){System.out.println("ticket="+ticket--);}}return "ticket sold out!";}
}

通过查看源码可以发现Thread类里面没有提供支持Callable接口的多线程应用。

通过继续查看源码可以发现,FutureTask< V >类,这个类主要是负责Callable接口对象操作,这个类的结构定义如下:

public class FutureTask<V> implements RunnableFuture<V>

RunnableFuture接口继承了Runnable接口和Future接口:

public interface RunnableFuture<V> extends Runnable, Future<V> {/*** Sets this Future to the result of its computation* unless it has been cancelled.*/void run();
}

FutureTask类中有如下的构造方法:

/*** Creates a {@code FutureTask} that will, upon running, execute the* given {@code Callable}.** @param  callable the callable task* @throws NullPointerException if the callable is null*/public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}

这个构造方法接收Callable接口对象或者继承了Callable接口对象的类,以此使得这个类能接收call方法的返回结果,从而放入值,而FutureTask又间接实现了Runnable接口和Future接口,Future接口的get方法负责取出值。

完整的Callable接口实现多线程的例子如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class test {public static void main(String[] args) throws ExecutionException, InterruptedException {MyThread mt1=new MyThread();MyThread mt2=new MyThread();FutureTask<String> task1=new FutureTask<String>(mt1);FutureTask<String> task2=new FutureTask<String>(mt2);//FutureTask是Runnable接口的实现类/子类,所以Thread构造方法可以接收其对象new Thread(task1).start();new Thread(task2).start();//FutureTask同时是Future接口的实现类/子类,父接口的get方法可以获取其值System.out.println("A"+task1.get());System.out.println("B"+task2.get());}
}class MyThread implements Callable<String>{private int ticket=10;@Overridepublic String call() throws Exception{for(int i=0;i<200;i++){if(this.ticket>0){System.out.println("ticket="+ticket--);}}return "ticket sold out!";}
}

输出结果如下:

这种实现方式的麻烦之处在于既要接收返回值信息,并且又要与原始的多线程的实现靠拢。

通过Callable和FutureTask创建线程相关推荐

  1. Java创建线程的三种方式,以前只知道两种,现在添加一种Callable与FutureTask创建的方式

    一共有以下三种方式: 1.继承Thread 2.实现Runnable 3.实现Callable,并FutureTask包装 线程启动方式均是使用start()方法 先阐述优缺点: 1和2,3: 2,3 ...

  2. 【头歌实训】Java高级特性 - 多线程基础(1)使用线程,使用 Callable 和 Future 创建线程

    任务描述 本关任务:通过 Callable 和 Future 来创建线程. 相关知识 从Java1.5版本开始,就提供了 Callable 和 Future 来创建线程,这种方式也是在Java程序员面 ...

  3. java回调原理,以及Callable和FutureTask通过回调机制创建可监控的线程

    回调的概念会JS的人应该都能理解. 回调分异步回调,同步回调.但是同步回调其实没什么意义.都同步了,那么直接等那边执行完了,这边再执行就可以了,没必要通过回调.我们说的回调主要是讲异步回调.用于两个线 ...

  4. 创建线程的三种方式、线程运行原理、常见方法、线程状态

    文章目录 1.创建线程的三种方式 1.1 继承Thread类并重写run方法 1.2 使用Runnable配合Thread 1.3 通过Callable和FutureTask创建线程 2.Runnab ...

  5. Java多线程 - Java创建线程的4种方式

    文章目录 1. Java创建线程有哪几种方式? 1.1 线程创建方法一:继承Thread类创建线程类 1.2 线程创建方法二:实现Runnable接口创建线程目标类 1.5 线程创建方法三:使用Cal ...

  6. Java基础教程——多线程:创建线程

    多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...

  7. 创建线程都有哪些方式?— Callable篇

    今天我们来看一道面试题引发的思考 问: 创建线程都有哪些方式? 答: 我了解的有四种创建方式: 继承Thread类创建线程类 通过Runnable接口创建线程类 通过Callable和Future创建 ...

  8. 创建线程(Lock()、线程池、Callable())及线程通信

    package com.xt.java;import java.util.concurrent.locks.ReentrantLock;/*** 解决线程安全问题的方式三:Lock锁 -->JD ...

  9. 【多线程】采用Callable接口创建线程

    前言 java5开始,提供了Callable接口,是Runable接口的增强版.同样用Call()方法作为线程的执行体,增强了之前的run()方法.因为call方法可以有返回值,也可以声明抛出异常. ...

  10. 创建线程的第三种方式:实现Callable接口(含部分源码解析)

    创建线程的第三种方式--实现Callable接口 package com.lqy.Multithreading; import java.util.concurrent.Callable; impor ...

最新文章

  1. 实现简书个人中心UI效果
  2. 雪鹰领主服务器维护,《雪鹰领主》7月14日维护更新公告
  3. kubernetes学习笔记 (二):k8s初体验
  4. php 命令链模式,设计模式之------命令链模式
  5. mysql for update_mysql SELECT FOR UPDATE语句使用示例
  6. 大数据挑战与NoSQL数据库技术pdf
  7. lamp 测试mysql_搭建LAMP测试环境
  8. websockets_Websockets在数据工程中鲜为人知的模式
  9. Inspection工具窗口
  10. SQLMAP使用教程(一)
  11. 苹果app旧版本软件下载
  12. QQ远程提示系统权限原因暂时无法操作怎么办
  13. dbi与dbd的含义与区别
  14. 金色十月线上编程比赛第二题:解密
  15. PCB板用基板材料分类
  16. 龙瀛:大数据在城市设计中的应用(附演讲视频)
  17. DialogUtil
  18. 电信说的几兆带宽和自己看到的下载/上传速度有什么关系
  19. 开发一个简单的APP到底需要多少钱
  20. 互联网企业盈利模式全分析二

热门文章

  1. Flutter之Widget 更新机制updateChild原理浅析
  2. ImageLoader的简单分析(终结篇)
  3. 为什么 Flink 无法实时写入 MySQL?
  4. 弃用 Notepad++,还有5款更牛逼的选择!
  5. Android 10正式版发布,支持5G和折叠屏设备
  6. 我用Python又爬虫了拉钩招聘,给你们看看2019市场行情
  7. dbeaver查看执行计划_SAP学习基础篇(52):PP模块-物料需求计划
  8. mysql 主从 日志_mysql主从复制基于日志复制
  9. mysql实现分布式锁_数据库实现分布式锁
  10. python-gui-pyqt5的使用方法-8--实际案例可参考使用