JUC并发编程-ThreadFuture

FutureTask

在这里插入图片描述

1. Future

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

2. RunnableFuture

RunnableFuture接口继承了Runable接口和Future接口

  • Runable接口使得RunnableFuture具有了通过Thread类执行的能力
  • Future接口使得其具有可获取任务信息的能力

更像一个适配器,对Runable接口进行了适配,同时还可以获取执行结果


public interface RunnableFuture<V> extends Runnable, Future<V> {
   //继承自Runnbale
    void run();
}

3. FutureTask

3.1 重要的属性
//任务执行的状态
/* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/  
private volatile int state;
private static final int NEW          = 0;//新建
private static final int COMPLETING   = 1;//完成未设置结果
private static final int NORMAL       = 2;//完成已设置结果
private static final int EXCEPTIONAL  = 3;//异常
private static final int CANCELLED    = 4;//被取消
private static final int INTERRUPTING = 5;//打断中
private static final int INTERRUPTED  = 6;//已被打断

//需要执行的任务
private Callable<V> callable;
//运行结果
private Object outcome; // non-volatile, 
//执行任务的线程
private volatile Thread runner;
//等待获取结果的线程队列(链表)
private volatile WaitNode waiters;
static final class WaitNode {
    volatile Thread thread;
    volatile WaitNode next;
    WaitNode() { thread = Thread.currentThread(); }
}
3.2 重要的方法
3.2.1 新建任务
//构造方法
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;//设置需要执行的任务
    this.state = NEW;//设置任务执行的状态为新建状态
}
3.2.2 执行任务

​ 因为FutureTask类实现了Runnable接口,因此FutureTask可以当作Thread的构造参数,当执行Thread执行start方法,其会自动执行FutureTask的run方法

run方法

public void run() {
    //state != NEW 验证任务状态是否是new状态
    //UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread())cas设置执行任务的线程为当前线程,此处记录执行线程是为了后面任务的打断和取消
    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 {
                result = c.call();//直接调用callble的call方法,获取执行结果
                ran = true;//设置执行成功
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);//如果出现异常,则设置状态为exception状态,并唤醒等待结果的线程
            }
            if (ran)
                set(result);//如果运行成功,则设置结果
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

set方法设置运行结果

protected void set(V v) {
    //cas设置状态为 执行完成COMPLETING
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;//设置结果
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // 设置最终状态,已经设置结果
        finishCompletion();//任务完成(包括出现异常)的处理
    }
}
/**
这里 putOrderedInt 是一个轻量级的操作,因为state是一个volatile修饰的
volatile能够使得变量保持线程间的可见性,其原理是加上了内存屏障 
+ 保证写volatile变量会强制把CPU写缓存区的数据刷新到内存
+ 读volatile变量时,使缓存失效,强制从内存中读取最新的值
+ 由于内存屏障的存在,volatile变量还能阻止重排序
它实际上是load 和store的组合,在写入前后读入前后添加load和store的组合指令。
其中:storeload是最重的,用来保证 写变量与读变量不进行重排序,同时保证可见性
但是有时候不需要让共享变量的修改立刻让其他线程可见的时候,所以可以使用store-store的方式只保证上次写与当前写不发生重排序,只是以设置普通变量的方式来修改共享状态,可以减少不必要的内存屏障,从而提高程序执行的效率。
*/

**finishCompletion方法 ** 任务完成(包括出现异常)的处理

主要是等待着的唤醒

private void finishCompletion() {
    //自旋 进行 cas设置等待队列为null
    for (WaitNode q; (q = waiters) != null;) {
        
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
            //遍历等待获取结果的线程(等待者)
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);//如果等待队列不为null则唤醒队列头对应的线程
                }
                //遍历下一个等待者线程
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null;//help gc
                q = next;
            }
            break;
        }
        //else 如果不成功则自旋,重新cas
    }

    done();

    callable = null;        // to reduce footprint
}
3.2.3 获取结果

get方法

public V get() throws InterruptedException, ExecutionException {
    int s = state;//获取当前的状态
    if (s <= COMPLETING)//如果小于COMPLETING 说明任务为完成,需要进行阻塞
        s = awaitDone(false, 0L);
    
    //report会根据执行任务的状态确定是返回结果还是抛出异常
    return report(s);
}

awaitDone(boolean timed, long nanos) 阻塞直到 任务执行完成

//timd nanos参数:如果timd为true,则最大能忍受nanos时间的阻塞,即使获取不到也会被唤醒
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;//获取最大忍受时间
    WaitNode q = null;//如果取消入队,则将自己放入包装到这个变量中,并插入到等待队列上
    boolean queued = false;//是否已经入队
    /*
    自旋:
    */
    for (;;) {
        //判断是否被打断:当阻塞过程中,线程可能被打断,需要自行检查,并抛出异常
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }
		/*
		根据不同的状态 做不同的对待:
        1.当state > COMPLETING:说明任务已经执行完成(包括结果已经设置、出现异常、打断以及取消等情况)
        	+ 返回即可
        2.当state == COMPLETING:说明任务虽然已经执行完成,但是还未设置结果
            + 已经快完成了,可以利用Thread.yield()让出CPU,使对应的线程快速执行完。进入下一次循环(自旋)
        3.当state < COMPLETING && q==null 表示还未为自己创建WaitNode
        	+ 为自己创建WaitNode,进入下一次循环(自旋)
        4.已经创建WaitNode,还未排队
        	+ 将自己插入到队列中,头插;进入下一次循环(自旋)
        5.已经进行了排队,需要限期获取结果
        	计算时间是否到期:
        		+ 如果到期,则移除等待队列上的WaitNode
        		+ 没到期:LockSupport.parkNanos(this, nanos);带有阻塞时间的阻塞
        6.已经进行了排队,无限期获取结果
        	+ 阻塞
        	
       注意:以上6中情况,每第i中情况一定不符合前i-1中情况,设计者通过自旋来尽量的减少阻塞带来的开销,但是最多自旋3次(在任务比较重未被完成的情况下),就陷入阻塞或者返回。
       
        */
        int s = state;
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();//让出cpu,让其他线程执行,尽量让任务的结果在这段时间内被设置
        else if (q == null)
            q = new WaitNode();
        else if (!queued)//cas插入队列
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
        else if (timed) {
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q);
                return state;
            }
            LockSupport.parkNanos(this, nanos);
        }
        else
            LockSupport.park(this);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值