设为首页 加入收藏

TOP

Java - ThreadPoolExecutor线程池分析(五)
2023-09-09 10:25:58 】 浏览:109
Tags:Java ThreadPoolExecutor 程池分
mentWorkerCount(); // 返回null,交接processWorkerExit移除当前工作线程 return null; } // ==================判断工作线程数量====================== // 拿到工作线程数 int wc = workerCountOf(c); // allowCoreThreadTimeOut: 是否允许核心线程超时(默认false) // 工作线程是否大于核心线程 boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; // 工作线程是否已经大于最大线程数 // 工作线程大于核心线程数,并且当前线程已超时 // 尝试干掉当前线程 if ((wc > maximumPoolSize || (timed && timedOut)) // 工作线程数大于1,或者工作队列为空 // 如果工作线程队列,就干掉自己 // 如果工作线程数大于1,就干掉自己 && (wc > 1 || workQueue.isEmpty())) { // 基于CAS的方法移除当前线程,只有一个线程会CAS成功 if (compareAndDecrementWorkerCount(c)) // 返回null,交接processWorkerExit移除当前工作线程 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; } } }

runWorker方法中processWorkerExit方法

//  移除当前工作线程
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    /*
     * 如果执行processWorkerExit方法的操作不是getTask中的操作,
     * 是直接因为异常引起的。(一般是勾子函数抛出异常导致的)
     */
    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();
    }

    //  尝试将线程池关闭(到TIDYING过度状态 - TERMINATED销毁状态)
    tryTerminate();

    //  重新获取ctl
    int c = ctl.get();
    //  判断当前状态是否小于STOP, 能进入说明是RUNNING、 SHUTDOWN
    if (runStateLessThan(c, STOP)) {
        //  如果是正常状态移除当前工作线程
        if (!completedAbruptly) {
            //  核心线程数最小值 ,允许核心线程超时就是0
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            //  如果工作队列中的任务不为空,设置工作线程的最小值为1
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            //  还有工作线程在线程池中
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        //  1. 说明是不正常的方式移除当前工作线程,那需要在添加一个非核心线程
        //  2. 线程池工作队列不为空,并且没有工作线程,需要在添加一个非核心线程
        addWorker(null, false);
    }
}

  

线程池为啥要构建空任务的非核心线程?

  • 第一个:在 execute 方法中有个判断工作线程是否为0,是就添加一个空任务的非核心线程;
else if (workerCountOf(recheck) == 0)
    addWorker(null, false);
  • 第二个:在工作线程 Worker 启动后,工作线程会运行 runWorker 方法,该方法中有个操作,当工作线程结束之后会执行 processWorkerExit 方法,在这个方法内部又有添加一个空任务的非核心线程;
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; // replacement not needed
        }
        addWorker(null, false);
    }
}

综合上诉,Java它有一个这样的场景:

在初始化线程池的时候可能设置线程池的核心线程数为0 或者 设置allowCoreThreadTimeOut(默认false)为ture导致核心线程超时释放,存在没有核心线程的情况。

当我们把任务添加到阻塞队列之后,没有工作线程导致阻塞队列任务堆积,直到后续有新任务加入才会去创建工作线程。

/**
 * If false (default), core thr
首页 上一页 2 3 4 5 6 下一页 尾页 5/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇简述Spring Cache缓存策略 下一篇14、Spring之基于注解的声明式事务

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目