线程池原理FutureTask,你懂了吗?


前言

线程池顾名思义,是放线程的池子,线程池在项目中使用的还是比较多的,那为什么要用线程池呢?主要有以下优势:

  1. 复用线程可以降低系统的资源消耗。
  2. 通过已有线程来处理请求,可以提高系统响应效率。
  3. 方便管理线程,保证系统的稳定性,防止并发量大而导致无限制创建线程产生OOM等问题。
  4. 提供更强大的功能,如延时定时线程池等。
    下面通过分析ThreadPoolExecutor类的源码来介绍线程池原理。

一、ThreadPoolExecutor结构体系

如下图:
在这里插入图片描述

Executor

Executor作为线程池的顶级接口,只有一个execute方法

public interface Executor {
	/**
	* 执行一个任务,但并不要求是同步执行还是异步执行,这取决于实现者。
	* command表示一个需要执行的任务
	*/
	void execute(Runnable command);
}

ExecutorService

ExecutorService扩展了Executor接口,添加了获取任务返回值的sumbit方法,关闭线程池的shutDown和shutDownNow等方法

public interface ExecutorService extends Executor {
	/**
	* 关闭线程池,但会把提交给线程池的任务都执行完再关闭
	*/
    void shutdown();
    
    /**
    * 立即关闭线程池,给正在执行的任务发中断指令,并返回队列中未执行的任务
    */
    List<Runnable> shutdownNow();
	
	/**
	* 线程池是否被关闭
	*/
    boolean isShutdown();

    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

AbstractExecutorService

AbstractExecutorService作为一个抽象类实现了ExecutorService接口,并实现了该接口的部分方法,最主要的是实现了submit方法,这里也只介绍sumbit方法。

public abstract class AbstractExecutorService implements ExecutorService {
	/**
	* 入参是Runnable,返回值为Future
	* 这个方法的关键逻辑主要是newTaskFor方法和execute方法。
	*/
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
    /**
    * 这个方法仅仅是将Runnable转换成一个RunnableFuture,具体实现在FutureTask构造方法中
    */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
}

二、FutureTask类结构体系

FutureTask类结构体系
在这里插入图片描述
FutureTask类实现了RunnableFuture接口,而RunnableFuture接口又扩展了Future和Runnable接口。

Future

Future接口代表了异步任务的结果。有获取任务结果的方法get(),还有取消任务的方法cancel(),

public interface Future<V> {
	/**
	* 取消任务
	*/
    boolean cancel(boolean mayInterruptIfRunning);
	/**
	* 任务是否被取消
	*/
    boolean isCancelled();
	/**
	* 任务是否完成
	*/
    boolean isDone();
	/**
	* 获取任务计算结果,阻塞直到任务完成
	*/
    V get() throws InterruptedException, ExecutionException;
	/**
	* 获取计算任务,阻塞指定的时间,如果还没有获取到则抛出TimeoutException
	*/
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

Runnable

Runnable作为Thread的顶级接口只有一个run方法。没有返回值不抛出异常。

public interface Runnable {
    void run();
}

也看下Callable接口,也是只有一个call方法,但有返回值,也可以抛出异常。

public interface Callable<V> {
    V call() throws Exception;
}

RunnableFuture

RunnableFuture接口整合了Runnable和Future接口,表示一个Future也是一个Runnable.

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * 执行该方法成功则会设置一个Future在结果中
     */
    void run();
}

之前看到ExecutorService接口的submit方法有Runnable参数,也有Callable参数的方法,从newTaskFor方法可以看到都封装在了FutureTask中。接下来我们看看FutureTask类。

FutureTask

FutureTask作为RunnableFuture一个实现类

主要属性

	/**
	*  任务的执行状态,volatile修饰,保证可见性
	* 初始化的时候为NEW状态,状态可能的变化过程:
	* NEW -> COMPLETING -> NORMAL   -- 正常执行
    * NEW -> COMPLETING -> EXCEPTIONAL	-- 抛出异常
    * 以上两种情况在run()方法中设置的,以下两种情况实在cancel方法中设置的
    * 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;

    /** 封装的callable,Runnable也封装在里面 */
    private Callable<V> callable;
    /** get方法的返回结果,也可能是一个Exception */
    private Object outcome; // non-volatile, protected by state reads/writes
    /** 执行这个callable的线程 */
    private volatile Thread runner;
    /** 等待者 */ 
    private volatile WaitNode waiters;
// WaitNode仅仅是封装了当前线程的单向链表
static final class WaitNode {
  volatile Thread thread;
    volatile WaitNode next;
    WaitNode() { thread = Thread.currentThread(); }
}

构造方法

两个构造函数,一个接收Callable,一个接收Runnable.

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) {
	// 将Runnable转换为Callable,这里使用的是适配器模式
    this.callable = Executors.callable(runnable, result); 
    this.state = NEW;       // ensure visibility of callable
}

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}
// 适配器模式:实现目标接口,依赖原接口,目标接口方法调用原有接口方法,从而达到适配的目的
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

关键方法

V get()

该方法可以在任务执行完成之后获取任务的返回值,如果任务没有执行完则一直阻塞。

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)// 表示是初始状态或处理中状态,需要阻塞直到执行成功
        s = awaitDone(false, 0L);
    return report(s);
}
/**
* 等待完成 或 因中断或超时而中止
* timed:是否使用时间等待
* nanos:使用时间等待的时间,单位纳秒
*/
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;// 等待截至时间,0表示无线等待
    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) // 如果正在执行任务,则让出cpu时间片
            Thread.yield();
        else if (q == null) // 表示在初始状态
            q = new WaitNode();
        else if (!queued) // 第二次循环仍然在初始状态
            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 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);
}
run()

从之前的submit方法源码中可以看出,execute(futureTask)将futureTask作为Runnable执行了,所以会执行这个run()方法。
run方法对真正要执行的任务进行了控制,如果不是NEW状态就不会执行任务,执行的结果或者异常放outcome属性中,然后改变state。

public void run() {
	// 先将runner设置为当前线程,不是新建状态直接返回
    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(); // 这里会去调用真正的方法
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex); // 设置异常
            }
            if (ran)
                set(result); // 设置返回结果
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s); // 等待state变成已中断
    }
}
// NEW -> COMPLETING(瞬间) -> EXCEPTIONAL(最终)
protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion(); // 唤醒所有等待的线程
    }
}
// NEW -> COMPLETING(瞬间) -> NORMAL(最终)
protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

cancel(boolean mayInterruptIfRunning)

取消任务。如果任务状态不为NEW,即任务已经执行完成,则直接返回false。
if mayInterruptIfRunning == true. NEW -> INTERRUPTING -> 修改线程中断标志 -> INTERRUPTED(终态)
else NEW -> CANCELLED(终态)

public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW && // 如果不是NEW状态,直接返回false
          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;
}
runAndReset()

执行这个任务但不设置结果,状态还是初始状态(NEW),可以重复执行多次。方法逻辑跟run()方法完全一样,只是少了设置结果这一步。

protected boolean runAndReset() {
    if (state != NEW || // 如果不是新建状态直接返回false
        !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;
}

FutureTask总结

FutureTask封装了执行者Runner和需要执行的任务Callable。然后通过状态state控制任务的执行,但这种控制我认为只能算是伪控制,无法控制正在进行的任务-,只能控制设置结果和改变中断标志位。
值得注意的是,在任务执行的过程中状态还是NEW,任务执行完成之后才会将NEW状态改变,所以在调用cancel方法的时候,如果任务没有执行,那么直接修改状态使任务不会再执行,但如果任务已经在执行中了,也仅仅是控制不设置任务返回结果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值