FutureTask源码解析(1)

目录

1 概述
2  FutureTask所使用到的接口
 2.1 Future接口
3  FutureTask所使用到的类
 3.1 Executor类
 3.2 UnSafe类


1 概述

FutureTask是一个任务可取消的任务异步计算类,该类实现Future接口,实现了启动与取消任务的方法。当计算完成后,通过get方法可以获取计算结果,get方法是个block方法,直接到任务完成才能返回计算结果。

2 FutureTask所使用到的接口

2.1 Future接口

Future接口被设计用来代表一个异步操作的执行结果。你可以用它来获取一个操作的执行结果、取消一个操作、判断一个操作是否已经完成或者是否被取消,获取执行结果只能通过get方法获取,get方法是一个阻塞方法,会等待计算完成返回执行结果。

public interface Future<V> {
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
    
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    
    boolean isDone();
}

Future接口一共定义了5个方法:

  • get()
    该方法用来获取执行结果, 如果任务还在执行中, 就阻塞等待;
  • get(long timeout, TimeUnit unit)
    该方法同get方法类似, 所不同的是, 它最多等待指定的时间, 如果指定时间内任务没有完成, 则会抛出TimeoutException异常;
  • cancel(boolean mayInterruptIfRunning)
    该方法用来尝试取消一个任务的执行, 它的返回值是boolean类型, 表示取消操作是否成功。

有以下三种情况之一的,cancel操作一定是失败的:
1、任务已经执行完成了
2、任务已经被取消过了
3、任务因为某种原因不能被取消
其它情况下,cancel操作将返回true。值得注意的是,cancel操作返回true并不代表任务真的就是被取消了,这取决于发动cancel状态时任务所处的状态:
1、如果发起cancel时任务还没有开始运行,则随后任务就不会被执行;
如果发起cancel时任务已经在运行了,则这时就需要看mayInterruptIfRunning参数了:

2、如果mayInterruptIfRunning 为true, 则当前在执行的任务会被中断
3、如果mayInterruptIfRunning 为false, 则可以允许正在执行的任务继续运行,直到它执行完。

  • isCancelled()

该方法用于判断任务是否被取消了。如果一个任务在正常执行完成之前被cancel掉了, 则返回true

  • isDone()

如果一个任务已经结束, 则返回true。注意, 这里的任务结束包含了以下三种情况:

  1. 任务正常执行完毕
  2. 任务抛出了异常
  3. 任务已经被取消

3 FutureTask使用到的类


3.1 Executors
3.2 Unsafe

Unsafe类对于并发编程来说是个很重要的类,J.U.C里的源码(你会发现到处充斥着这个类的方法调用。这个类的最大的特点在于,它提供了硬件级别的CAS原子操作。

CAS可以说是实现了最轻量级的锁,当多个线程尝试使用CAS同时更新同一个变量时,只有其中的一个线程能成功地更新变量的值,而其他的线程将失败。然而,失败的线程并不会被挂起。

CAS操作包含了三个操作数:需要读写的 内存位置,进行比较的原值,拟写入的新值

在Unsafe类中,实现CAS操作的方法是: compareAndSwapXXX

例如:

public native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);
  • obj是我们要操作的目标对象
  • offset表示了目标对象中,对应的属性的内存偏移量
  • expect是进行比较的原值
  • update是拟写入的新值。

所以该方法实现了对目标对象obj中的某个成员变量(field)进行CAS操作的功能。那么,要怎么获得目标field的内存偏移量offset呢? Unsafe类为我们提供了一个方法:

public native long objectFieldOffset(Field field);

该方法的参数是我们要进行CAS操作的field对象,要怎么获得这个field对象呢?最直接的办法就是通过反射了:

Class<?> k = FutureTask.class;
Field stateField = k.getDeclaredField("state");

我们就能对FutureTask的state属性进行CAS操作

除了compareAndSwapObject,Unsafe类还提供了更为具体的对int和long类型的CAS操作:

public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);
public native boolean compareAndSwapLong(Object obj, long offset, long expect, long update);

从方法签名可以看出,这里只是把目标field的类型限定成int和long类型,而不是通用的Object.

最后,FutureTask还用到了一个方法:

public native void putOrderedInt(Object obj, long offset, int value);

可以看出,该方法只有三个参数,所以它没有比较再交换的概念,某种程度上就是一个赋值操作,即设置obj对象中offset偏移地址对应的int类型的field的值为指定值,但不保证值的改变被其他线程立即看到,只有在field被\color{red}{volatile}修饰并且期望被意外修改的时候使用才有用。
与putOrderedInt方法相似的方法\color{red}{putOrderedInt}

public native void putIntVolatile(Object obj, long offset, int value);

该方法设置obj对象中offset偏移地址对应的整型field的值为指定值,支持volatile变量可见性。由此可以看出,当操作的int类型field本身已经被volatile修饰时,putOrderedInt和putIntVolatile是等价的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容