Java源码学习之高并发编程基础——多线程的创建(下)

1.前言&目录

前言:

在上一篇文章Java源码学习之高并发编程基础——多线程的创建(上)中,讲解了Java中多线程的创建(无返回值)以及基本的运作机制,但是还有其他方式同样可以实现多线程,比如有返回值的FutureTask。

因此,本文将继续以类和接口源码解读的方式,讲解有返回值的多线程编程方式——FutureTask。

目录:

1.前言&目录

2.源码分析

 2.1  Future接口源码剖析

 2.2  RunnableFuture接口源码剖析

 2.3  Callable接口源码剖析

 2.4  FutureTask类源码剖析

2.4.1 FutureTask#run()方法源码剖析

2.4.2  FutureTask#get()方法源码剖析

2.4.3 FuturueTask#cancel()方法

2.4.4 FutureTask#isCancelled()方法

2.4.5 FutureTask#isDone()方法

2.5  实现有返回值的多线程

3.总结

2.源码分析

Java源码学习之高并发编程基础——多线程的创建(上)中,详细介绍了线程的运行逻辑,本质上无论是继承Thread还是实现Runnable接口,最终的底层实现都是需要借助Thread#start()方法去调用C语言方法,通过它让JVM创建更小的执行单元去执行run()方法,这就是多线程编程的基本原理。

但是后来C语言没有实现有返回值的多线程,而是Java1.5版本以后,通过创建了几个接口、类完美的实现了获取多线程执行的返回值。这些接口和类的设计恰到好处,即充分体现了面向对象的特性,实际上也运作的很好。

这些接口和类分别是Future接口、RunnableFuture接口、Callable接口、FutureTask类,接下来将逐一分析它们的源码。

2.1  Future接口源码剖析

Future接口是一个泛型接口,其目的是为了接受多线程中不同类型的返回结果。那么它存在的意义是什么?

实际上,在Java中定义接口,是为了定义一个规范。如果你想获取多线程执行的结果那么就必须实现此接口。并且在实践中,线程池中处理有返回值的多线程也是用Future去接收返回结果的。

如下,它一共有五个抽象方法,比较常用的获取返回结果的有两个get方法,一个是没有设置超时时间的,即会一直阻塞到多线程的结果返回。另一个则是设置了超时时间,即最多会等待timeout的时间,超过时间仍然没有获取到结果则会抛出TimeoutException。

public interface Future<V> {
    // 尝试取消任务执行,前提是任务处于可以被取消的状态
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();// 如果此任务在正常完成前已取消,则返回true
    boolean isDone(); // 判断当前任务是否完成(包含计算中,正常完成,发生异常) 
    // 没有超时时间的获取方法,会一直阻塞到结果返回
    V get() throws InterruptedException, ExecutionException;
    // 有超时时间的获取方法,如果超时时间已过还没拿到结果则抛出异常
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

剩下三个方法,由于不同的实现类有不同的实现,因此不在这里进行深入讲解,将在后面讲解2.4  FutureTask类源码剖析时深入分析,但注意它们的返回值都是布尔类型。 

2.2  RunnableFuture接口源码剖析

如果说Future接口是定义能获取多线程执行结果的规范,那么这个RunnableFuture接口的作用就是将Thread和Future衔接起来。

 在Java中,多线程的执行有且仅有一种方式,就是通过调用Thread实例start()方法进而调用native的C语言方法,让其在操作系统层面创建一个更小的执行单元去执行Thread实例的run()方法。

但是无论在Thread#run()还是Runnable#()run()方法,都是无返回值的。因此在Java1.5以后,为了支持能获取多线程编程中的返回结果,定义了Future接口。为了可以接入到Thread,也定义了一个RunnableFuture的泛型接口。

如下伪代码所示,它继承了Runnable接口和Future接口。其目的就是为了即能借助Thread去实现多线程编程也能获取返回结果。

public interface RunnableFuture<V> extends Runnable, Future<V> {
    // 有返回值的多线程在此方法设置返回值
    void run();
}

继承Runnable接口,意味着实现RunnableFuture接口的实现类本质上也是一个Runnable实例,可以直接将其作为Thread的构造函数入参去创建一个Thread实例。

继承Future接口,意味着实现RunnableFuture接口的实现类必须重写其抽象方法,其中就包括两个获取返回的结果的get方法。

后面将要讲解的FutureTask正是实现了RunnableFuture接口,也就是说FutureTask即承担着Thread实例的成员属性(Runnable)target目标对象的角色、也拥有获取返回结果的能力。

2.3  Callable接口源码剖析

Callable接口的设计正是为了能获取多线程编程的返回结果而生,它是一个泛型接口,也就是说实现此接口的类必须明确返回结果类型。

 从结构上看,它和Runnable接口非常相似,两者都是函数式接口(即可以直接使用lamada表达式去代替创建一个类并重写抽象方法)。

不同的是,Runnable#run()方法没有返回值并且也没声明异常,Callable#call()有返回值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值