首页 > 代码库 > JDK之线程池分析

JDK之线程池分析

线程池组成

一个线程池包括以下四个基本组成部分:
                1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
                2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
                3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
                4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

线程池种类

1、newSingleThreadExecutor

创建一个单线程的线程池,以无界队列方式运行。这个线程池只有一个线程在工作(如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。)此线程池能够保证所有任务的执行顺序按照任务的提交顺序执行,同一时段只有一个任务在运行。

               此类型线程池特别适合于需要保证执行顺序的场合。

2、newFixedThreadPool

创建固定大小的线程池,以无界队列方式运行。线程池满且线程都为活动状态的时候如果有新任务提交进来,它们会等待直到有线程可用。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。显式调用shutdown将关闭线程池。

此类型线程池比较符合常用场合。

3、newCachedThreadPool

创建一个可缓存的线程池。必要的时候创建新线程来处理请求,也会重用线程池中已经处于可用状态的线程。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程;当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

此类型线程池特别适合于耗时短,不需要考虑同步的场合。

4、newScheduledThreadPool

创建可定时运行(初始延时),运行频率(每隔多长时间运行,还是运行成功一次之后再隔多长时间再运行)的线程池。

此类型线程池适合定时以及周期性执行任务的场合。

线程池的jdk实现

corePoolSize的作用

在生成的线程池ThreadPoolExecutor中,有一个corePoolSize属性,它的作用是用来判断是否要创建新的线程,如果当前线程池中线程的数量大于corePoolSize,则有空闲线程则使用,没有空闲线程则创建线程。如果小于corePoolSize则不管怎样,都会从新创建线程。

    /**
     * Core pool size, updated only while holding mainLock, but
     * volatile to allow concurrent readability even during updates.
     */
    private volatile int   corePoolSize;

执行线程池的execute方法时,不同的线程池种类不同的响应

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
            if (runState == RUNNING && workQueue.offer(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
            else if (!addIfUnderMaximumPoolSize(command))
                reject(command); // is shutdown or saturated
        }
    }

工作线程Worker

工作线程执行它的run方法后,会一直试图去等待队列里面取出任务

        /**
         * Main run loop
         */
        public void run() {
            try {
                hasRun = true;
                Runnable task = firstTask;
                firstTask = null;
                while (task != null || (task = getTask()) != null) { //注意getTask()方法,它会循环着去取出来任务
                    runTask(task);
                    task = null;
                }
            } finally {
                workerDone(this);
            }
        }

看getTask()方法

它会循环去取出来任务,

    Runnable getTask() {
        for (;;) {
            try {
                int state = runState;
                if (state > SHUTDOWN)
                    return null;
                Runnable r;
                if (state == SHUTDOWN)  // Help drain queue
                    r = workQueue.poll();
                else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                else
                 r = workQueue.take(); //注意这一句话,对于固定大小的线程池和可缓冲的线程池,使用的队列类型不一样,一个时阻塞队列,一个是同步队列
                if (r != null)
                    return r;
                if (workerCanExit()) { // 获取不到任务时,对于可缓冲队列有一个退出机制
                    if (runState >= SHUTDOWN) // Wake up others
                        interruptIdleWorkers();
                    return null;
                }
                // Else retry
            } catch (InterruptedException ie) {
                // On interruption, re-check runState
            }
        }
    }






JDK之线程池分析