并发编程(六)

109 阅读5分钟

这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

线程池

比较核心的类

ThreadPoolExcutor

ScheduledExecutorService

ScheduledThreadPoolExecutor

ThreadPoolExecutor

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private final BlockingQueue<Runnable> workQueue;
private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet<Worker> workers = new HashSet<Worker>();

ctl 是线程池状态(高3位)和线程的个数(低29位)

mainLock是内部变量互斥访问控制

works线程集合

 private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {

        private static final long serialVersionUID = 6138294804551838833L;
        final Thread thread;
        Runnable firstTask;
        volatile long completedTasks;
        Worker(Runnable firstTask) {
            setState(-1); 
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }
 }

work本身就是一把锁

核心参数

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

处理流程

  • 判断当前线程数是否大于或等于corePoolSize, 如果小于新建线程执行
  • 判断队列是否已满, 如果未满,放入队列
  • 判断当前线程数是否大于或等于maxPoolSize,如果小于,新建线程处理
  • 根据拒绝策略,拒绝任务

优雅关闭

  • 生命周期

    • RUNNING: Accept new tasks and process queued tasks
    • SHUTDOWN: Don't accept new tasks, but process queued tasks
    • STOP: Don't accept new tasks, don't process queued tasks,and interrupt in-progress tasks
    • TIDYING: All tasks have terminated, workerCount is zero,the thread transitioning to state TIDYING will run the terminated() hook method
    • TERMINATED: terminated() has completed
executor.shutdown();
boolean flag = true;
do{
    flag = !executor.awaitTermination(500, TimeUnit.MILLISECONDS);
}while(flag);
public boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (;;) {
            if (runStateAtLeast(ctl.get(), TERMINATED))
                return true;
            if (nanos <= 0)
                return false;
            nanos = termination.awaitNanos(nanos);
        }
    } finally {
        mainLock.unlock();
    }
}

钩子方法

protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
protected void terminated() { }

shutdown和shutdownNow

  • shutdown不会清空任务队列, 会等所有任务执行完成,shutdownNow清空任务队列
  • shutdown只会中断空闲的线程, shutdownNow会中断所有线程

源码分析

  • 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();
        }
        //添加到队列
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //工作线程是否为0
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }
    
  • addWorker

    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
    
            // 线程池状态不会,第一个任务为null或者队列空
            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;
                //增加worker成功
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                //运行状态为shutdown, 重试 
                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 {
            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()) 
                            throw new IllegalThreadStateException();
                        //添加到worker集合
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                //启动线程
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
    
  • Work #run

    Worker(Runnable firstTask) {
        setState(-1);
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    
    public void run() {
        runWorker(this);
    }
    
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        //中断线程
        w.unlock(); 
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        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);
        }
    }
    
    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
    
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
    
            int wc = workerCountOf(c);
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
    
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
    
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
    
    private void processWorkerExit(Worker w, boolean completedAbruptly) {
            if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
                decrementWorkerCount();
    
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                completedTaskCount += w.completedTasks;
                workers.remove(w);
            } finally {
                mainLock.unlock();
            }
            tryTerminate();
            int c = ctl.get();
            if (runStateLessThan(c, STOP)) {
                if (!completedAbruptly) {
                    int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                    if (min == 0 && ! workQueue.isEmpty())
                        min = 1;
                    if (workerCountOf(c) >= min)
                        return; 
                }
                addWorker(null, false);
            }
        }
    

拒绝策略

  • AbortPolicy : 抛出异常
  • CallerRunsPolicy 任务在自己线程执行
  • DiscardPolicy 直接丢弃
  • DiscardOldestPolicy 丢弃最早的任务

工具类

  • singleThreadExecutor
  • fixedThreadPool
  • cachedThreadPool
  • scheduledThreadPool
  • singleThreadScheduledExecutor

ScheduledThreadPoolExecutor

执行延迟任务和周期执行任务

AtFixedRate按固定频率执行,与任务执行时间无关, 任务执行时间必须小于间隔时间

WithFixedDelay按固定间隔执行, 与任务执行时间有关

是通过DelayedWOrkQueue来实现的,底层原理和DelayQueue一样,针对任务的取消进行了优化。

CompletableFuture

常用方法

  • runAsync 与supplyAsync

    runAsync没有返回值, supplyAsync有返回值。

  • thenRun, thenAccept, thenApply

    不用通过get获取,直接能拿到结果

  • thenCompose, thenCombine

    thenCompose取消嵌套, 传入的参数是Function类型, 返回值是CompletionStage子类

    thenCombine传入supplier函数和BIFunction,将supplier的返回值和前面的值结合起来做些操作

  • 组合 allOf anyOf

四种任务原型

  • Runnable: runAsync thenRun
  • Consumer: thenAccept
  • Supplier: supplierAsync
  • Function: thenApply

CompletionStage原理

CompletableFuture不仅实现了Future接口,还实现了CompletableStage接口, 所有方法返回值都是自己。默认情况下依赖ForkJoinPool

 private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
  • 任务类型的适配

    supplyAsync方法内部会把Supplier方法转换成AsyncSupply,提交给ForkJoinPool执行。

    runAsync会把run方法转换成AsyncRun

    thenRun/thenApply/thenAccept会转换成UniRun/uniApply/uniAccept

  • 任务链式执行

    每个CompletableFuture内部都有一个栈,存储的是后续依赖它的任务,这个栈是Treiber Stack。

thenApply和thenApplyAsync的区别

前置任务没有执行,都会将当前任务的下个任务入栈

当前任务执行完毕, thenApply立刻会在当前线程执行, 不会入栈。thenApplyAsync会在forkJoinPool执行,入栈出栈

allOf 和anyOf

allOf中每两个生成BiRelay,BiRelay只是中转任务,本身没有任务代码,只是参照输入的两个Future是否完成,如果完成就从栈中弹出依赖他的BiRelay继续执行

ForkJoinPool

分治算法的多线程并行计算框架,需要任务继承RecursiveAction或RecursiveTask。RecursiveAction没有返回值,RecursiveTask有返回值。

核心数据结构

public class ForkJoinPool extends AbstractExecutorService {

    //状态变量
    volatile long ctl;  
	//工作队列--工作窃取队列
    volatile WorkQueue[] workQueues;    
    //线程工厂
    final ForkJoinWorkerThreadFactory factory;
	//下一个Work的下标
    int indexSeed;
    static final class WorkQueue {
             
        
        //线程的局部队列
        ForkJoinTask<?>[] array;   
        final ForkJoinPool pool;  
        //所有者线程, null表示共享
        final ForkJoinWorkerThread owner; 
    }
}

public class ForkJoinWorkerThread extends Thread {
     final ForkJoinPool pool;                
    final ForkJoinPool.WorkQueue workQueue; 
}
private ForkJoinPool(int parallelism,
                         ForkJoinWorkerThreadFactory factory,
                         UncaughtExceptionHandler handler,
                         int mode,
                         String workerNamePrefix) {
    this.workerNamePrefix = workerNamePrefix;
    this.factory = factory;
    this.ueh = handler;
    this.config = (parallelism & SMASK) | mode;
    long np = (long)(-parallelism); // offset ctl counts
    this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}

工作窃取

这个队列有两个操作:

  • Worker线程在队列头部,对top指针执行加,减,单线程
  • 其他worker线程在队列尾部,对base进行累加,执行出队,多线程,CAS操作

特点:

  • 队列是环形的,base一直累加,不会减少,top会累加,减少
  • 队列满了会扩容,扩容会变成2倍的大小

状态控制

ctl被分为五部分

  • 最高的16个比特位标识Active线程数-parallelism
  • 次高的16个比特位标识Total线程数
  • 1个比特位,如果是1,表示整个ForkJoinPool正在关闭
  • 15个比特位,标识阻塞栈的栈定线程的wait count
  • 16个比特位,标识阻塞栈的栈顶线程对应的ID

阻塞栈

把所有空闲的work线程放在一个栈里, 也就是TreiberStack

状态

  • 空闲状态,在阻塞栈里
  • 活跃状态, 在执行ForkJoinTask,未阻塞
  • 阻塞状态 在执行ForkJoinTask,但阻塞了