JAVA并发编程-线程池理解

线程数、核心线程数量如何设置

        我们知道在线程池创建过程中2个重要参数

        corePoolSize:核心线程数

        maximumPoolSize:最大线程数

       通常我们怎么设置呢?

理论上

        将任务分为CPU密集型、IO密集型、及混合型。

        CPU密集型:CPU核心数+1

                为什么要+1,在多线程中,如果当前线程中断,CPU就会让出当前线程调度其他线程,这里+1就是充分利用CPU资源

        IO密集型:2*CPU核心数

        通用公式: CPU 核心数  * (1 + 线程等待时间 / 线程运行总时间)

实际上

        当然现实中一个系统中不可能只有我们当前一个线程池在运行,根据理论值配置,对项目接口进行压测,在保证响应时间的情况下,根据压测结果动态调整线程数量。

线程池的执行方法

  1.    void execute(Runnable command)    
  2.    Future<?> submit(Runnable task)
  3.    invokeAll()  //执行一组任务,按任务集合保存结果
  4.    invokeAny()  //执行一组任务,返回任意一个执行成功的结果
  5.  schedule()  //延迟执行或者定期执行

线程池的执行流程

  1. 通过execute()或submit()方法提交任务到线程池; 
  2. 如果当前工作线程数 < corePoolSize,创建新线程执行任务,即使有空闲线程也创建新线程(直到达到corePoolSize)

  3. 如果工作线程数 ≥ corePoolSize,尝试将任务放入工作队列

  4. 如果队列未满,任务加入队列等待执行

  5. 如果队列已满且工作线程数 < maximumPoolSize,创建临时线程执行任务

  6. 如果队列已满且工作线程数 = maximumPoolSize,触发拒绝策略

线程的五种状态流转

RUNNING:接收新任务并且处理队列中的任务

SHUTDOWN:不会接收新任务并且处理队列中的任务

STOP:不会接收新任务并且不会处理队列中的任务,并且会中断在处理的任务

TIDYING:所有任务都终止了,线程池中也没有线程了,这样线程池的状态就会转为TIDYING,一旦达到此状态,就会调用线程池的terminated()

TERMINATED:terminated()执行完之后就会转变为TERMINATED

这五种状态并不能任意转换,只会有以下几种转换情况:

  1. RUNNING -> SHUTDOWN:手动调用shutdown()触发
  2. (RUNNING or SHUTDOWN) -> STOP:调用shutdownNow()触发,如果先调shutdown()紧着调shutdownNow(),就会发生SHUTDOWN -> STOP
  3. shutdownNow(),就会发生SHUTDOWN -> STOP
  4. SHUTDOWN -> TIDYING:队列为空并且线程池中没有线程时自动转换
  5. STOP -> TIDYING:线程池中没有线程时自动转换(队列中可能还有任务)
  6. TIDYING -> TERMINATED:terminated()执行完后就会自动转换

线程池中的线程是如何关闭的?

        非核心线程数回收

  • 条件:当线程空闲时间超过keepAliveTime且当前线程数大于corePoolSize

  • 过程:线程池会主动终止这些多余的线程

  • 效果:线程数量逐渐减少到corePoolSize

        

  核心线程数回收

        要设置 executor.allowCoreThreadTimeOut(true);

使用shutdown() / shutdownNow() 中断,底层 interrupt()来中断线程

源码解析

        基本属性

        

//这个下面用到,高低位,高3位,设置线程池状态,后29位设置线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 32-3 = 29
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; // 线程数量掩码

// 线程池状态,存储在高位
private static final int RUNNING    = -1 << COUNT_BITS; // 接受新任务并处理队列中任务
private static final int SHUTDOWN   =  0 << COUNT_BITS; // 不接受新任务,但处理队列中任务
private static final int STOP       =  1 << COUNT_BITS; // 不接受新任务,不处理队列中任务,中断进行中任务
private static final int TIDYING    =  2 << COUNT_BITS; // 所有任务已终止,线程数为0,转换为TERMINATED前的状态
private static final int TERMINATED =  3 << COUNT_BITS; // 终止状态

// 从ctl中提取线程数
private static int workerCountOf(int c) { return c & CAPACITY; }
// 从ctl中提取运行状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
//从ctl里面提取运行状态(runState)和线程数(workerCount)合并为一个整数值
private static int ctlOf(int rs, int wc) { return rs | wc; }

初始化方法

        并没有立刻创建所有核心数,在调用execute时创建,属于一种懒加载。

        但是在Tomcat类中ThreadPoolExecutor是在初始化时创建所有核心线程数

execute方法

        流程:

1.检查任务是否为空,若为空则抛出NullPointerException。
2.如果当前线程数小于核心线程数,尝试创建新线程执行任务。如果成功,则返回;否则重新获取状态。
3.如果线程池处于运行状态且任务能成功入队,则再次检查线程池状态:
        如果线程池已停止,移除任务并拒绝执行。
        如果线程池中没有线程,尝试创建一个空闲线程。
4.如果任务无法入队,尝试创建新线程执行任务。如果失败,则拒绝任务。

 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);
            //如果线程池中没有线程,尝试创建一个空闲线程,针对核心线程回收情况(allowCoreThreadTimeOut 设置为true)
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
         /**
        如果任务无法入队,尝试创建新线程执行任务。如果失败,则拒绝任务
         **/
        else if (!addWorker(command, false))
            reject(command);
    }

addWorker方法

        分为2部分,第一部分双重循环找出一个要创建的线程,第二部分创建线程并加入works工作集合。

  private boolean addWorker(Runnable firstTask, boolean core) {
        /**
            双循环找出需要创建的线程对象
        **/
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //如果线程池状态是shutdown及以上 或者 shutown此时队列有数据,不创建返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                //获取工作线程数
                int wc = workerCountOf(c);
                //大于核心或者最大线程数,根据参数core判断,返回false
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //cas比较,如:同时有2个线程走到这里,cas成功的跳出for循环在,走到第二步生成新线程加入工作集合;不成功的再循环一次
                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线程对象
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    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) {
                    //加成功,运行线程
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            //如果不成功,销毁刚新增的线程
            if (! workerStarted) 
                addWorkerFailed(w);
        }
        return workerStarted;
    }

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 {
            //循环获取任务
            while (task != null || (task = getTask()) != null) {
                //加锁
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                /**
                    检查线程池是否处于停止状态(STOP)或更高状态,如果是,则确保当前线程被中断。
如果线程池未停止,清除线程的中断状态,但需要重新检查以处理 shutdownNow 调用时可能发生的竞争条件。
                **/
                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);
        }
    }

processWorkerExit方法

 private void processWorkerExit(Worker w, boolean completedAbruptly) {
        /**
            处理突然终止的线程:如果 completedAbruptly 为 true,表示线程因异常终止,未调整线程计数,因此调用 decrementWorkerCount 减少线程计数。
        **/
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            /**
            更新已完成任务数和移除线程:加锁后,增加已完成任务数 completedTaskCount,并将线程从 workers 集合中移除。
            **/
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        //尝试终止线程池:调用 tryTerminate 检查是否可以终止线程池
        tryTerminate();

        int c = ctl.get();
        /**
            判断是否需要补充线程:
                如果当前运行状态小于 STOP:
                    若线程非异常终止,计算最小线程数 min(取决于是否允许核心线程超时)。
                    如果当前线程数大于等于最小线程数,则无需补充线程。
                    否则,调用 addWorker 添加新线程。
         **/
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }

tryTerminate方法

        尝试更改线程池状态

 final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            /**
                如果是运行状态,或者队列不为空,不处理
            **/
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //如果还有工作线程,中断线程
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                   /**
                        CAS则尝试将状态设置为 TIDYING,
                    调用 terminated 方法,并最终将状态设置为 TERMINATED。
                    **/
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

getTask方法

        获取任务方法

        

 private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //线程池状态大于0 且 (状态为1 或 队列为空) 线程数-1
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            //工作线程数大于核心线程数
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            //(工作线程数大于最大线程数 || 第一次(true&&false))
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                //cas减少线程
                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;
            }
        }
    }

       done ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值