美文网首页
newFixedThreadPool原理

newFixedThreadPool原理

作者: snakeSkin | 来源:发表于2017-05-16 21:43 被阅读1207次

    @(Executors)[newFixedThreadPool]

    [TOC]

    java线程池

    在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。

    newFixedPool作用

    创建一个固定线程数的线程池,在任何时候最多只有nThreads个线程被创建。如果在所有线程都处于活动状态时,有其他任务提交,他们将等待队列中直到线程可用。如果任何线程由于执行过程中的故障而终止,将会有一个新线程将取代这个线程执行后续任务。

    构造方法

    newFixedPool拥有两个构造方法:

    参数为nThreads的构造方法:

     public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
    

    构造方法中的nThreads代表固定线程池中的线程数,当使用此构造方法创建线程池后,就会创建nThreads个线程在线程池内。
    参数为: nThreads,ThreadFactory的构造方法:

      public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>(),
                                          threadFactory);
        }
    

    ThreadPoolExecutor构造方法

    newFixedThreadPool(int nThreads) 使用的构造方法:

        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }
    

    此ThreadPoolExecutor构造方法的参数有5个:
    corePoolSize:线程池中所保存的线程数,包括空闲线程,newFixedThreadPool中传入nThreads
    maximumPoolSize:池中允许的最大线程数,newFixedThreadPool中传入nThreads,使线程池的最大线程数与线程池中保存的线程数一致,使保证线程池的线程数是固定的
    TimeUnit:参数的时间单位
    keepAliveTime:当线程数大于corePoolSize时,此为终止前多余的空闲线程等待新任务的最长时间
    LinkedBlockingQueue workQueuqe:当任务被执行前,放到此阻塞队列中,任务将被放在阻塞队列中直到使用execute方法提交Runnable任务,不同的线程池主要是这个参数的不通,比如scheduledThreadPoolExecutor这边使用的就是DelayedWorkQueue这个队列

    **注意:
    * The queue used for holding tasks and handing off to worker
    * threads. We do not require that workQueue.poll() returning
    * null necessarily means that workQueue.isEmpty(), so rely
    * solely on isEmpty to see if the queue is empty (which we must
    * do for example when deciding whether to transition from
    * SHUTDOWN to TIDYING). This accommodates special-purpose
    * queues such as DelayQueues for which poll() is allowed to
    * return null even if it may later return non-null when delays
    * expire.
    */

        private final BlockingQueue<Runnable> workQueue;
    

    newFixedThreadPool(in nThreads,ThreadFactory threadFactory)使用的构造方法:

     public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>(),
                                          threadFactory);
        }
    
        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);   //创建默认线程工厂,并设置驳回的异常处理
        }
    
    

    创建ThreadPoolExecutor时传入Executors.defaultThreadFactory()这个默认线程工厂实例。
    在代码中调用ThreadPoolExecutor中的内部类DefaultThreadFactory工厂,在包中的注释是这么写的:threadFactory the factory to use when the executor creates a new thread 。这是用来使用executor创建新线程的工厂。

    static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
    
        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }
    
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
    
    

    调用DefaultThreadFactory的构造方法初始化线程组和生成线程前缀。在创建完线程工厂后,需要使用线程工厂来创建线程并启动。

    使用线程池中的线程执行Runnable任务

    当之前的初始化(corePoolSize等于maxiumPoolSize等于nThreads,并创建defaultThreadFactory)就可以运行定义好的线程了。
    执行线程的代码如下:

        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            /*
             * Proceed in 3 steps:
             *
             * 1. If fewer than corePoolSize threads are running, try to
             * start a new thread with the given command as its first
             * task.  The call to addWorker atomically checks runState and
             * workerCount, and so prevents false alarms that would add
             * threads when it shouldn't, by returning false.
             *
             * 2. If a task can be successfully queued, then we still need
             * to double-check whether we should have added a thread
             * (because existing ones died since last checking) or that
             * the pool shut down since entry into this method. So we
             * recheck state and if necessary roll back the enqueuing if
             * stopped, or start a new thread if there are none.
             *
             * 3. If we cannot queue task, then we try to add a new
             * thread.  If it fails, we know we are shut down or saturated
             * and so reject the task.
             */
            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);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);
        }
    

    其中最重要的方法是addWorker,其方法目的是创建Worker对象,并将Worker对象加入到HashSet<Worker> workers中。在加入workers之前,先创建ReentrantLock排它锁,将worker同步的加入到workers中。当worker成功被加入后,启动本次放入set中的线程。

      private boolean addWorker(Runnable firstTask, boolean core) {
            retry:
            for (;;) {
                int c = ctl.get();
                int rs = runStateOf(c);
    
                // Check if queue empty only if necessary.
                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 w = null;
            try {
                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;
        }
    
    

    Worker对象的构造方法:

    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    
    

    通过线程工厂 来创建线程。

     public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    
    

    相关文章

      网友评论

          本文标题:newFixedThreadPool原理

          本文链接:https://www.haomeiwen.com/subject/oyocxxtx.html