线程池(FutureTask)

1、任务提交 

// 创建线程池提交任务
ExecutorService executorService = Executors.newFixedThreadPool(1);
for (int i=0;i<3;i++){
  // 提交任务,由AbstractExecutorService#submit实现
executorService.submit(()->{
        System.out.println(Thread.currentThread().getName());
    });
}
Thread.sleep(500);
executorService.shutdown();

//=========================上述逻辑执行流程代码分析===================
//AbstractExecutorService#submit,有三个重载方法
// 提交Runnable类型的任务,不带有返回值
public Future<?> submit(Runnable task)
// 提交带有返回值的Runnable,其中返回值为null(要想从线程池中获取执行结果,需要提交Callable类型任务)
public <T> Future<T> submit(Runnable task, T result)
// 提交Callable类型的任务,自带返回结果
public <T> Future<T> submit(Callable<T> task)
// 以Runnable类型任务为例
public Future<?> submit(Runnable task) {
  // 入口检查,防止提交null
    if (task == null) throw new NullPointerException();
  // 类型转换,统一将提交的任务转换成RunnableFuture,其实是转换成FutureTask(FutureTask是RunnableFuture的一种实现)
    RunnableFuture<Void> ftask = newTaskFor(task, null);
  // 任务提交的真正入口
    execute(ftask);
  return ftask;
}
//AbstractExecutorService#newTaskFor
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}
//FutureTask#构造
public FutureTask(Runnable runnable, V result) {
   // 使用适配器模式,将Runnable类型任务转成Callable类型,底层依赖于RunnableAdapter
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}
// ThreadPoolExecutor#execute
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
   // 获取线程池状态
    int c = ctl.get();
   // 线程池线程个数小于核心线程数,该情况下直接将当前任务放入线程池执行
    if (workerCountOf(c) < corePoolSize) {
     // 条件成立,说明放入线程池成功(会启动一个新线程执行该任务)
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
   // 执行到这,前提条件有两个 1、核心线程数已到,需要排队 2、线程池放入失败,执行入队
   // 入队失败后执行在构建线程池对象设定的拒绝策略
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

// 添加worker(worker是线程池中之行任务的线程,循环的从队列中获取任务执行),对用的逻辑是在线程池中开启线程
private boolean addWorker(Runnable firstTask, boolean core) {
   // 这些是一些条件判断,直接略过
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 将提交的任务包装成worker(FutureTask实现了RunnableFuture,RunnableFuture实现了Runnable,故可以用Runnable表示提交的任务)
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
          // 获取线程池运行状态
                int rs = runStateOf(ctl.get());
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
          // 启动worker执行任务,worker开始运行,执行worker的run方法
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}
// Worker#run ,线程池中任务处理
public void run() {
    runWorker(this);
}

2、任务执行

// ThreadPoolExecutor#runWorker 线程池中任务处理核心逻辑
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
        // 循环从任务队列中获取任务,任务来源有两种。1、任务提交的原始任务,此时线程池未满,直接构建线程执行 2、等待队列中获取 。队列获取任务是阻塞操作,队列为空时,线程会阻塞等待任务提交
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
               // 任务最终执行处。通过submit方法向线程池中提交的任务都是被转换成FutureTask类型,并重写了run方法。故此处执行的是FutureTask中重写的run方法
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

// FutureTask#run
public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
     // 提交的任务,不管是Runnable还是Callable都会被转换为Callable
        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;
           // 异常,使用get方法会得到该异常信息
                setException(ex);
            }
            if (ran)
          // 正常执行,结果设置
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

// FutureTask#set正常结果设置
protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
     // 线程池执行结果
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
     // 任务执行完成之后的处理,用于唤醒线程池任务还没执行完成之前调用get方法获取结果导致阻塞的线程。这些被阻塞的线程会被放入阻塞队列
        finishCompletion();
    }
}

// FutureTask#setException 同上,只是是异常
protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}
// 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;
           // 阻塞队列中有值,表示有线程在调用get方法时被阻塞。现在结果已出,需要唤醒被阻塞的线程
                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
}

3、获取结果

// FutureTask#get 获取向线程池提交任务的执行结果
public V get() throws InterruptedException, ExecutionException {
   // 获取当前任务执行的状态
    int s = state;
   // 条件成立表示任务正在执行中,当前获取结果线程需要放入等待队列并阻塞
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

// FutureTask#awaitDone等待执行结果
private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
   // get操作如果指定超时则使用,否则为0,表示不需要超时逻辑
    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;
        }
     // 条件成立,出现的可能是,任务已经完成,但是还没有将执行结果赋值给outcome。这种情况下不需要阻塞
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
       // 这种情况是第一次进入排队逻辑。需要将当前调用get方法的线程封装成WaitNode。在第二次进入时,如果任务还没有执行完成,需要 入队
        else if (q == null)
            q = new WaitNode();
        else if (!queued)
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
     // 下面的逻辑是park逻辑。被唤醒后表示结果已具备,获取执行结果然后跳出循环,完成取数操作
        else if (timed) {
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q);
                return state;
            }
       // park当前线程(带有超时)
            LockSupport.parkNanos(this, nanos);
        }
        else
       // park当前线程
            LockSupport.park(this);
    }
}

4、流程分析图

 

posted @ 2022-11-07 15:26  多少幅度  阅读(82)  评论(0)    收藏  举报