线程池原理

187 阅读4分钟
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new Runnable() {
              @Override
              public void run() {
                 System.out.println("原理解析");
              }
         });

这是一个很简单的线程池案例,第一步就是初始化一个线程池,然后进行各种参数的设置,主要有四种线程池类型,可以去看下源码,主要是队列的不同。具体细节可以去网上搜。我们主要看下execute()方法。其实是调用了ThreadPoolTaskExecutor类的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();
        }
        **判断下当前线程池是否处于Running状态,线程池状态不同,执行的策略也是不同的,参考上面这幅图,并且能成功加入队列
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            **这里又判断了线程池的状态,因为在多线程环境下,有可能线程一执行到此处的时候线程二修改了线程池状态,所以要再判断一下
            **如果线程不处于Running状态,就拒绝接受新任务,就将该任务移除掉
            if (! isRunning(recheck) && remove(command))
                **执行拒绝策略
                reject(command);
            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);

            **也是对线程池状态进行判断
            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对象是实现了Runnable接口的,所以肯定有run方法,这里是重点,先记着
        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();
                        workers.add(w);
                        int s = workers.size();
                        **largestPoolSize参数是用来记录线程池出现过的最大线程数
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    **这里的start方法就是调用Worker类的run方法,所以我们进入run方法看看
                    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(); 
        boolean completedAbruptly = true;
        try {
            **判断当前任务是否为空,或者队列中是否为空,这个getTash()方法很重要,线程存活时间就是在这里判断的
            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 {
                        **这里的run方法就是在我们文章开头那个案例中的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);
        }
    }

我们看下这个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,我们知道addWorker会执行Worker类中的runWorker方法,那里有个很重要的判断
            ** while (task != null || (task = getTask()) != null) 在这里task = null,所以我们看下getTask方法
            addWorker(null, false);
        }
    }

接下来看下getTask方法做了什么

       **这个方法是从队列中获取需要执行的任务
       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 {
                    **从队列中获取任务,keepAliveTime这个参数就是在我们初始化线程池的时候给的线程存活时间,如果在这个时间内没有获取到任务,直接返回null,如果有任务继续执行
                    Runnable r = timed ?
                        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                        workQueue.take();
                    if (r != null)
                        return r;
                    timedOut = true;
                } catch (InterruptedException retry) {
                    timedOut = false;
                }
            }
        }
以上纯属个人理解,有错误欢迎提出,其中还有另外三种线程池,四种的拒绝策略