目录
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。注意, 这里的任务结束包含了以下三种情况:
- 任务正常执行完毕
- 任务抛出了异常
- 任务已经被取消
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被修饰并且期望被意外修改的时候使用才有用。
与putOrderedInt方法相似的方法
public native void putIntVolatile(Object obj, long offset, int value);
该方法设置obj对象中offset偏移地址对应的整型field的值为指定值,支持volatile变量可见性。由此可以看出,当操作的int类型field本身已经被volatile修饰时,putOrderedInt和putIntVolatile是等价的。
网友评论