线程池的实现原理

线程池处理流程

(1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程

(2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了。则进入下一个流程

(3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行。如果已经满了,则交给饱和策略来处理这个任务。

线程池主要处理流程

java线程池执行越来越慢 怎么优化 java线程池工作流程_多线程


ThreadPoolExecutor执行execute()方法示意图

java线程池执行越来越慢 怎么优化 java线程池工作流程_并发编程_02

)

ThreadPoolExecutor执行execute()方法分下面4种情况

(1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(执行这一步骤需要获取全局锁)

(2)如果运行的线程等于或多余corePoolSize,则将任务加入到BlockingQueue。

(3)如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(执行这一步需要全局锁)

(4)如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecute完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。。
源码分析

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        使用原子类获取当前线程数AtomicInteger
        int c = ctl.get();
        工作线程小于核心线程数(corePoolSize)
        if (workerCountOf(c) < corePoolSize) {
        	将当前线程作为第一个任务启动新线程。
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        如果线程数少于30且能够在(BlockingQueue)阻塞队列中成功排队
        if (isRunning(c) && workQueue.offer(command)) {
        	重新检查工作数量
            int recheck = ctl.get();
            如果当前队列中的线程数大于30则将当前线程从队列中移除
            if (! isRunning(recheck) && remove(command))
            	拒绝执行当前任务
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        如果不能将线程排队,那么添加一个新线程,如果失败,任务已关闭或已饱和
        else if (!addWorker(command, false))
        	拒绝该任务
            reject(command);
    }

工作线程:线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行。

循环获取工作队列里的任务
    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
}
    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
                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);
        }
    }

ThreadPoolExecutor中线程执行任务示意图

java线程池执行越来越慢 怎么优化 java线程池工作流程_java线程池执行越来越慢 怎么优化_03


线程池中的线程执行任务分两种情况

(1)在execute()方法中创建一个线程时,会让这个线程执行当前任务

(2)这个线程执行完上图的任务1后,会反复从BlockingQueue获取任务来执行。