文章目录

  • 1. Runnable接口实例
  • 2. Callable接口原理
  • 3. Callnable接口实例
  • 4. FutureTask是什么?
  • 5. 线程池中 submit() 和 execute() 方法有什么区别?

Runnable接口源码:

@FunctionalInterface
public interface Runnable {// 这个run()方法返回值为void,没有受检异常的异常声明,出现异常只能内部捕获public abstract void run();
}

Callable接口源码:

@FunctionalInterface
public interface Callable<V> {// 这个call()方法有返回值,且声明了受检异常,可以直接抛出Exception异常V call() throws Exception;
}

Runnable接口和Callable接口的区别:

(1) Runnable接口中的唯一抽象方法run()方法没有返回值,Callable接口中的唯一抽象方法call()方法有返回值;

(2) Runnable接口的run()方法没有受检异常的异常声明,即异常只能在内部捕获,不能继续上抛, Callable接口的call()方法声明了受检异常,可直接抛出Exception异常,并且可以不予捕获;

(3) Callable实例不能和Runnable实例一样,直接作为Thread线程实例的target来使用;

(4) 异步执行任务在大多数情况下是通过线程池去提交的,而Runnable接口和Callable接口都可以应用于线程池;

(5) Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

注意:异步执行任务在大多数情况下是通过线程池去提交的,而很少通过创建一个新的线程去提交(即通过Thread类的方式执行start()方法)。

下面实例解析以上不同点:

1. Runnable接口实例

首先,通过实现Runnable接口的方式创建一个异步执行任务:

public class RunnableTask implements Runnable  {// 线程体:需要线程异步执行的任务@Overridepublic void run() {System.out.println("实现Runnable接口来编写异步执行任务");// run()方法内出现异常,只能捕获不能直接抛出try {Thread.sleep(1000) ;} catch (InterruptedException e) {e.printStackTrace();}}
}

方式1:通过Thread类创建线程,将Runnable接口的实现类作为Thread线程实例的target来使用,执行异步任务

public class RunnableDemo {public static void main(String[] args) {Runnable target = new RunnableTask();// 通过Thread类创建一个新线程,并启动Thread thread = new Thread(target);thread.start();}
}

方式2:通过线程池创建线程,并提交异步执行任务

public class RunnableDemo2 {// 通过线程池创建3个线程private static ExecutorService executorService = Executors.newFixedThreadPool(3);public static void main(String[] args) throws ExecutionException, InterruptedException {// 1、通过线程池的execute()方法提交异步执行任务,没有返回结果executorService.execute(new RunnableTaskDemo());// 2、通过线程池的submit()方法提交异步执行任务,有返回结果Future<?> submit = executorService.submit(new RunnableTaskDemo());// 获取返回结果System.out.println(submit.get()); // null}
}

2. Callable接口原理

Callable接口实例没有办法作为Thread线程实例的target来使用。既然如此,那么该如何使用Callable接口创建线程呢?因此需要一个在Callable接口与Thread线程之间起到搭桥作用的重要接口。

1、RunnableFuture接口源码:

public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}

RunnableFuture接口实现了2个目标:

(1) RunnableFuture通过继承Runnable接口,从而保证了其实例可以作为Thread线程实例的target目标;
(2) RunnableFuture通过继承Future接口,从而保证了可以获取未来的异步执行结果。

那有些同学可能疑惑了,Future接口又是什么?Future接口至少提供了3大功能:

(1) 能够取消异步执行中的任务;
(2) 判断异步任务是否执行完成;
(3) 获取异步任务完成后的执行结果;

2、Future接口的源码:

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;
}

Future接口中的方法:

  • get():获取异步任务执行的结果。注意,这个方法的调用是阻塞性的。如果异步任务没有执行完成,异步结果获取线程(调用线程)会一直被阻塞,一直阻塞到异步任务执行完成,其异步结果返回给调用线程。

  • get(Long timeout,TimeUnit unit):设置时限,(调用线程)阻塞性地获取异步任务执行的结果。该方法的调用也是阻塞性的,但是结果获取线程(调用线程)会有一个阻塞时长限制,不会无限制地阻塞和等待,如果其阻塞时间超过设定的timeout时间,该方法将抛出异常,调用线程可捕获此异常。

  • boolean isDone():获取异步任务的执行状态。如果任务执行结束,就返回true。

  • boolean isCancelled():获取异步任务的取消状态。如果任务完成前被取消,就返回true。

  • boolean cancel(boolean mayInterruptRunning):取消异步任务的执行。

总体来说,Future是一个对异步任务进行交互、操作的接口。但是Future仅仅是一个接口,通过它没有办法直接完成对异步任务的操作,JDK提供了一个默认的实现类——FutureTask。

3、FutureTask类 :

RunnableFuture只是一个接口,无法直接创建对象,如果需要创建对象,就需用到它的实现类——FutureTask。所以说,FutureTask类才是真正的在Thread与Callable之间搭桥的类。FutureTask类实现了RunnableFuture接口,而RunnableFuture接口又继承了Runnable接口和Future接口,因此它可以作为Thread线程实例的target目标,也可以获取异步执行结果;

public class FutureTask<V> implements RunnableFuture<V> {}

FutureTask内部有一个Callable类型的成员——callable实例属性:

private Callable<V> callable;

callable实例属性用来保存并发执行的Callable类型的任务,并且callable实例属性需要在FutureTask实例构造时进行初始化:

public FutureTask(Callable<V> callable) {if (callable == null) throw new NullPointerException();// callable实例属性需要在FutureTask实例构造时进行初始化this.callable = callable;this.state = NEW;       // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable
}

FutureTask类实现了Runnable接口,在其run()方法的实现版本中会执行callable成员的call()方法:

public void run() {if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {// 在run()方法中执行call()方法result = c.call();ran = true;} catch (Throwable ex) {// ...}if (ran) set(result);}} finally {// ...}
}

FutureTask内部还有另一个非常重要的Object类型的成员——outcome实例属性:

private Object outcome;

FutureTask的outcome实例属性用于保存callable成员call()方法的异步执行结果。在FutureTask类的run()方法完成callable成员的call()方法的执行之后,其结果将被保存在outcome实例属性中,供FutureTask类的get()方法获取。

3. Callnable接口实例

首先,通过实现Runnable接口的方式创建一个异步执行任务:

public class CallableTaskDemo implements Callable {// call()方法有返回值,并且可以抛出Exception异常@Overridepublic String call() throws Exception {System.out.println("实现Callable接口来编写异步执行任务");Thread.sleep(1000);return "返回线程执行结果";}
}

方式1:通过Thread类创建线程执行异步任务

public class CallableDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建异步执任务实例Callable callable = new CallableTaskDemo();// 初始化callable实例属性FutureTask futureTask = new FutureTask(callable);// 创建线程执行异步任务Thread thread = new Thread(futureTask);thread.start();System.out.println("获取异步执行任务结果:"+futureTask.get());// 获取异步执行任务结果:返回线程执行结果}
}

方式2:通过线程池创建线程,并提交异步执行任务:

public class CallableDemo2 {// 通过线程池创建3个线程private static ExecutorService executorService = Executors.newFixedThreadPool(3);public static void main(String[] args) throws ExecutionException, InterruptedException {// 通过线程池的submit()方法提交异步执行任务,有返回结果Future submit = executorService.submit(new CallableTaskDemo());// 获取返回结果System.out.println(submit.get());}
}

4. FutureTask是什么?

Future是一个对异步任务进行交互、操作的接口。但是Future仅仅是一个接口,通过它没有办法直接完成对异步任务的操作,JDK提供了一个默认的实现类——FutureTask。

对于Calleble来说,Future和FutureTask均可以用来获取任务执行结果,不过Future是个接口,FutureTask是Future的具体实现,而且FutureTask还间接实现了Runnable接口,也就是说FutureTask可以作为Runnable任务提交给线程池。

5. 线程池中 submit() 和 execute() 方法有什么区别?

两者都是将一个线程任务添加到线程池中并执行;
1、excutor没有返回值,submit有返回值,并且返回执行结果Future对象
2、excutor不能提交Callable任务,只能提交Runnable任务,submit两者任务都可以提交
3、在submit中提交Runnable任务,会返回执行结果Future对象,但是Future调用get方法将返回null(Runnable没有返回值)

Java多线程 - Runnable接口和Callable接口的区别相关推荐

  1. Java多线程(6)--Callable接口创建线程

    与使用Runnable相比, Callable功能更强大些 ①相比run()方法,可以有返回值 ②方法可以抛出异常 ③支持泛型的返回值 ④需要借助FutureTask类,可以获取返回结果 Future ...

  2. java多线程异步调用别的系统接口代码_抢先准备,40个 Java 多线程面试题及答案大汇总!...

    ↑↑↑点上方蓝字关注并标⭐「IT技术思维」 一起培养顶尖技术思维 来源:程序员共成长(id:finishbug) 这些多线程的问题,有些来源于各大网站.有些来源于自己的思考.可能有些问题网上有.可能有 ...

  3. 【Android 异步操作】FutureTask 分析 ( Future 接口解析 | Runnable 接口解析 | Callable 接口解析 )

    文章目录 一.Future 接口 1.Future 接口简介 2.取消任务方法 3.Future 接口源码注释 二.Callable 接口 三.Runnable 接口 上一篇博客 [Android 异 ...

  4. java多线程异步调用别的系统接口代码_60 多个实例讲解,彻底搞懂 Java 多线程!

    ​JAVA 最难学的部分是哪里?很多朋友都会说:「 java 多线程 」. 随着业务量和数据的增加,企业不可避免地会使用多线程的方式处理数据.在 Java 职位的面试中,多线程也是必考的高阶知识点之一 ...

  5. java callable接口_Java Callable接口实现细节详解

    代码如下 import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import ja ...

  6. Runnable接口和Callable接口的区别

    有点深的问题了,也看出一个Java程序员学习知识的广度. 1.Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已: 2.Callable接口 ...

  7. java callable接口_Java Callable接口

    一 理论 Runnable是执行工作的独立任务,但是不返回任何值.如果我们希望任务完成之后有返回值,可以实现Callable接口.在JavaSE5中引入的Callable是一个具有类型参数的范型,他的 ...

  8. Java多线程学习十三:synchronized 和 Lock 区别以及孰优孰劣,如何选择?

    synchronized 和 Lock 的异同点,以及该如何选择. 相同点 synchronized 和 Lock 的相同点非常多,我们这里重点讲解 3 个比较大的相同点 ABC. A:synchro ...

  9. JavaSE基础二十:Java 多线程(线程基础知识、Java 多线程、Java 实现多线程(继承 Thread 类、实现 Runnable 接口、实现 Callable 接口))

    本章目录 1.基础知识准备 2.Java 多线程概述 3.Java 实现多线程 3.1.继承 Thread 类 如何开启新线程 Thread 类常用方法 多线程中的同步 Thread 类同步方法 多线 ...

最新文章

  1. 转:经典论文翻译导读之《Google File System》
  2. 在C#中Java的最终版本相当于什么?
  3. pandas的reindex功能
  4. SHOI2016 黑暗前的幻想乡
  5. 极光推送收费标准_刚刚,安卓统一推送又有进展了!华为率先...
  6. SSH之Hibernate总结篇
  7. 小熊的人生回忆(二)
  8. 权限管理(1):简介
  9. 安装ssr_网易《代号SSR》电脑版教程!
  10. 写给创业者的四句金玉良言
  11. C++ Primer Plus 读书笔记(第4、5章)
  12. python教程简书_python基础教程
  13. 流程生产订单和离散生产订单的区别_离散式生产和流程式生产的区别
  14. 幼儿园管理云平台众多,只有一家与众不同
  15. 双系统下如何切换到ubantu界面及如何切换到windows界面
  16. caxa cam数控车2020破解版 v20.0.0.6460附安装教程|caxa数控车2020破解版
  17. 独立开发一款简单的安卓app
  18. php网站视频播放外链,视频直接上传到七牛上,在浏览器中输入外链为什么不能直接播放?...
  19. OC 建议实现类似淘宝的物流步骤视图
  20. Vue React大屏可视化进阶

热门文章

  1. 站住!不许动!放下DOCTYPE!
  2. DataGridView控件使用大全
  3. Ext4 vs XFS——你应该使用哪个文件系统
  4. keychain service钥匙串服务
  5. bzoj4275[ONTAK2015]Badania naukowe DP
  6. int short型类型转换
  7. matlab舍选法编程,利用舍选抽样法生成随机数.pdf
  8. Unity 生成原始LUT用于外部校色相机不透明物体截图
  9. 怎么将ppt文件压缩变小一点?
  10. vue element upload组件 file-list的动态绑定