线程池源码解析之FutureTask

本文详细解析了FutureTask的类继承关系、状态、属性、构造方法和核心方法。重点讨论了run(), setException(Throwable), set(V), finishCompletion(), handlePossibleCancellationInterrupt(int), runAndReset()以及get()等方法的实现原理,阐述了FutureTask如何处理任务的执行、取消和结果获取。" 138511842,19461490,Linux压缩与解压:tar和gzip命令详解,"['Linux', '运维', '服务器']
摘要由CSDN通过智能技术生成

一、简介

1. 类继承关系

FutureTask类图

2. 状态

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;

FutureTask状态图

二、属性

private volatile int state;
/** The underlying callable; nulled out after running */
private Callable<V> callable;
/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run() */
private volatile Thread runner;
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;

state表示FutureTask的状态。
FutureTask使用了delegate模式,callable就是其委派对象,具体的业务执行由callable对象进行。
由于FutureTask是Runnable的实现类,为了实现对callable任务的封装,可以获取callable的执行结果,FutureTask将callable的执行结果或者执行过程中抛出的异常保存在outcome中。
runner执行任务的线程
WaitNode 的定义如下,可以看到是一个链表式的结果,waiters表示等待中的线程集。

static final class WaitNode {
    volatile Thread thread;
    volatile WaitNode next;
    WaitNode() { thread = Thread.currentThread(); }
}

三、构造方法

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    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
}

分别根据runnable或者callable作为FutureTask的callable对象,并将状态初始化为NEW。

四、状态判断

public boolean isCancelled() {
    return state >= CANCELLED;
}

public boolean isDone() {
    return state != NEW;
}

isCancelled表示FutureTask是否被取消,包括CANCELLED, INTERRUPTING, INTERRUPTED。
isDone表示FutureTask是否已经进行过操作,包括取消操作和执行任务的操作。

五、核心方法

1. FutureTask#run()

FutureTask既然是Runnable的实现类,其run方法自然就是我们关注的重点。

public void run() {
    //检查并设置执行的线程
     if (state != NEW ||
         !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                      null, Thread.currentThread()))
         return;
     try {
         Callable<V> c = callable;
         //callable 和 state 检查
         if (c != null && state == NEW) {
             V result;
             boolean ran;
             try {
                 result = c.call();
                 ran = true;
             } catch (Throwable ex) {
                 result = null;
                 ran = false;
                 setException(ex);
             }
             if (ran)
                 set(result);
         }
     } finally {
     	//状态重置前runner必须不能为null,防止并发
         // runner must be non-null until state is settled to
         // prevent concurrent calls to run()
         runner = null;
         // state must be re-read after nulling runner to prevent
         // leaked interrupts
         int s = state;
         //中断处理
         if (s >= INTERRUPTING)
             handlePossibleCancellationInterrupt(s);
     }
 }
2. FutureTask#setExecption(Throwable)
protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}

异常赋值给outcome,设置状态,并调用finishCompletion进行收尾工作。
可以看到COMPLETING只是一个任务执行过程中的一个短暂的中间状态,用于防止并发。

3. FutureTask#set(V)
protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

setExecption是FutureTask的异常处理,而该方法则是正常完成的处理逻辑。
执行结果赋值给outcome,设置状态,并调用finishCompletion进行收尾工作。

4. FutureTask#finishCompletion
private void finishCompletion() {
    // assert state > COMPLETING;
    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);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }

    done();

    callable = null;        // to reduce footprint
}

(1)遍历waiters,将其中的线程移除并发送信号唤醒线程进行执行。
双重循环,外层循环用于CAS修改waiters为null值的失败重试,内层循环用于遍历waiters
(2)调用done方法。
done方法时执行完成时的钩子函数,FutureTask本身并没有做任何动作,留给子类进行扩展。

protected void done() { }

(3)callable置为null。

5. FutureTask#handlePossibleCancellationInterrupt(int)
/**
* Ensures that any interrupt from a possible cancel(true) is only
 * delivered to a task while in run or runAndReset.
 */
private void handlePossibleCancellationInterrupt(int s) {
    // It is possible for our interrupter to stall before getting a
    // chance to interrupt us.  Let's spin-wait patiently.
    if (s == INTERRUPTING)
        while (state == INTERRUPTING)
            Thread.yield(); // wait out pending interrupt

    // assert state == INTERRUPTED;

    // We want to clear any interrupt we may have received from
    // cancel(true).  However, it is permissible to use interrupts
    // as an independent mechanism for a task to communicate with
    // its caller, and there is no way to clear only the
    // cancellation interrupt.
    //
    // Thread.interrupted();
}

中断来自于在run和runAndReset方法执行过程中的cancel(true)操作,对于中断的处理就是通过线程让步的方式等待取消逻辑执行完成。

6. FutureTask#runAndReset()
/**
  * Executes the computation without setting its result, and then
  * resets this future to initial state, failing to do so if the
  * computation encounters an exception or is cancelled.  This is
  * designed for use with tasks that intrinsically execute more
  * than once.
  *
  * @return {@code true} if successfully run and reset
  */
 protected boolean runAndReset() {
     if (state != NEW ||
         !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                      null, Thread.currentThread()))
         return false;
     boolean ran = false;
     int s = state;
     try {
         Callable<V> c = callable;
         if (c != null && s == NEW) {
             try {
                 c.call(); // don't set result
                 ran = true;
             } catch (Throwable ex) {
                 setException(ex);
             }
         }
     } finally {
         // runner must be non-null until state is settled to
         // prevent concurrent calls to run()
         runner = null;
         // state must be re-read after nulling runner to prevent
         // leaked interrupts
         s = state;
         if (s >= INTERRUPTING)
             handlePossibleCancellationInterrupt(s);
     }
     return ran && s == NEW;
 }

runAndReset方法也用于执行任务,与run方法不同的是,该方法不修改状态,也不会处理执行结果,只返回是否执行成功,这是为了可以反复执行任务,主要的使用场景就是ScheduledFutureTask类。

7. FutureTask#get

FutureTask共有两个get方法用于获取任务的执行结果,分别是不限时的FutureTask#get()和限时的FutureTask#get(long, TimeUnit),两者的逻辑类似,以FutureTask#get(long, TimeUnit)为例解析

public V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException {
    if (unit == null)
        throw new NullPointerException();
    int s = state;
    if (s <= COMPLETING &&
        (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
        throw new TimeoutException();
    return report(s);
}

(1)null值检查
(2)如果当前任务未完成,阻塞等待一段时间
(3)如果等待一段时间后还未完成,抛出超时异常TimeoutException
(4)通过report方法返回执行结果。

8. FutureTask#report(int)
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

根据状态值返回不同的结果。
任务正常完成,返回执行结果
任务被取消,抛出异常CancellationException
任务异常结束,将抛出的异常封装成ExecutionException抛出

9. FutureTask#awaitDone(boolean, long)

同样有两个方法,用于get方法中等待任务完成或被取消,返回方法执行结束时的状态

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

         int s = state;
         if (s > COMPLETING) {
         //执行结束,返回
             if (q != null)
                 q.thread = null;
             return s;
         }
         else if (s == COMPLETING) // cannot time out yet
         //执行中,线程让步,将cpu执行时间段让出
             Thread.yield();
         else if (q == null)
        	 //封装成WaitNode,适用于刚进入循环的场景
             q = new WaitNode();
         else if (!queued)
         	//加入链表waiters
             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);
     }
 }
//链表移除指定节点
private void removeWaiter(WaitNode node) {
	if (node != null) {
	    node.thread = null;
	    retry:
	    for (;;) {          // restart on removeWaiter race
	        for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
	            s = q.next;
	            if (q.thread != null)
	                pred = q;
	            else if (pred != null) {
	                pred.next = s;
	                if (pred.thread == null) // check for race
	                    continue retry;
	            }
	            else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
	                                                  q, s))
	                continue retry;
	        }
	        break;
	    }
	}
}

在循环中进行检查,被中断或执行加上或超时后返回状态,否则封装成WaitNode并加入到waiters中,通过LockSupport.park进行阻塞。
可以看到,在finishCompletion方法中会通过LockSupport.unpark发送信号,取消线程的阻塞。

10. FutureTask#cancel(boolean)
public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();
    }
    return true;
}

只有在线程的状态为NEW(没有进行任何操作)时,才可以进行取消。
对于参数为false的场景,不进行线程中断,直接将状态修改为CANCELLED。
对于参数为true的场景,需要进行线程中断,将状态改为过渡值INTERRUPTING防止并发,然后发送中断信号后再修改状态值为INTERRUPTED,最后finishCompletion唤醒所有阻塞线程。
线程被中断不代表线程被取消,只是调用t.interrupt(),此时,如果t因为sleep(),wait()等方法进入阻塞状态,那么阻塞的地方会抛出InterruptedException;如果线程正常运行,需要结合Thread的interrupted()方法进行判断,才能结束,否则,cancel(true)不能结束正在执行的任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值