线程池(ThreadPoolExecutor)工作原理解读


几种常见线程池:
  • newScheduledThreadPool
    • 创建一个定长线程池,支持定时及周期性任务执行,可以作一个定时器使用。
  • newCachedThreadPool
    • 创建一个可缓存线程池,如果线程池长度超过需要的线程数量,可灵活回收空闲线程,若无可回收,则新建线程。
  • newSingleThreadExecutor
    • 创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行,可以控制线程的执行顺序。
  • newFixedThreadPool
    • 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待;当创建的线程池数量为1的时候,类似单线程化的线程池,当为1的时候,也可控制线程执行顺序。

常用阻塞队列:
  • ArrayBlockingQueue:基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,生产者放入数据和消费者获取数据,共用同一个锁对象,者无法真正并行运行。可以控制对象内部锁是否公平锁,默认采用非公平锁。ArrayBlockingQueue和LinkedBlockingQueue,前者插入或删除元素时不会产生或销毁任何额外对象,后者会生成一个额外Node对象。长时间内需要高效并发地处理大批量数据的系统中,其对于GC存在一定的影响。

  • LinkedBlockingQueue:基于链表的阻塞队列,能够高效的处理并发数据,因其对于生产者端和消费者端分别采用了独立的锁来控制数据同步,意味着在高并发的情况下生产者和消费者可以并行操作队列数据,以提高整个队列并发性能。没有指定容量大小,会默认无限大小容量(Integer.MAX_VALUE),如果生产者速度大于消费者速度,系统内存就有可能已被消耗殆尽了。

  • DelayQueue:当其指定的延迟时间到了,才能够从队列中获取到该元素。是一个没有大小限制的队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。

  • PriorityBlockingQueue:基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定),但需要注意的是并不会阻塞数据生产者,而只会在没有可消费的数据时,阻塞数据的消费者。

  • SynchronousQueue:一种无缓冲的等待队列。


常用拒绝策略:
  • AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • DiscardPolicy:丢弃任务,但是不抛出异常。
  • DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
  • CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务。

ThreadPoolExecutor
AbstractExecutorService
ExecutorService
Executor
execute:Runnable
submit:Runnable
submit:Callable

线程池源码解读:
  • ThreadPoolExecutor.execute(Runnable command)详解

ctl是一个Integer值,它是对线程池运行状态和线程池中有效线程数量标识字段,共32位,高3位表示"线程池状态",低29位表示"线程池中的线程数量"


private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }


在多线程环境,运行状态和有效线程数量统一,不能出现一个改而另一个未改的情况;将他们其放AtomicInteger中,利用原子操作,可以保证这两个值始终是统一的。


    // 线程池执行任务的方法
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();

        // 获取当前工作线程的数量
        int c = ctl.get();
        
        // 1、如果数量小于核心线程池的数量
        if (workerCountOf(c) < corePoolSize) {
            // 创建核心线程并执行任务
            // 添加成功返回
            if (addWorker(command, true))
                return;
                
            // 执行失败,重新获取工作线程数量
            c = ctl.get();
        }
        
        // 2、如果有效线程数大于等于核心线线程数,且程池是运行状态,尝试将任务加入阻塞队列
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            // 再次检查线程池的状态,如果不是运行中,移除刚才添加的任务
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 线程池中没有线程,增加一个线程
            // 主要是为了防止线程池的任务队列里有任务而没有线程可用的这种情况发生。
            else if (workerCountOf(recheck) == 0)
                //第一个参数为null,说明只为新建一个worker线程,没有指定firstTask
                //第二个参数为true代表占用corePoolSize,false占用maxPoolSize
                addWorker(null, false);
        }
        
        // 3、如果线程池不是running状态,或者放入阻塞队列失败,则尝试创建新线程执行任务,扩容至maxPoolSize
        // 如果创建线程失败,则调用拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }


    // 创建线程执行任务
    // core:true创建核心线程;false创建最大线程
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        
        /*
        作用是判断ctl变量当前的状态是否可以添加任务,
        特别说明了如果线程池处于SHUTDOWN状态时,
        可以继续执行阻塞队列中的任务,
        但不能继续往线程池中添加任务了;
        同时增加工作线程数量使用了AQS作同步,
        如果同步失败,则继续循环执行。
        */
        for (;;) {
            int c = ctl.get();
            // 获取线程池状态
            int rs = runStateOf(c);
            
            // 如果线程池不再接收新任务
            // 线程池状态为SHUTDOWN,可以继续执行阻塞队列中的任务,不能往线程池添加任务
            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;
                    
                // AQS增加有效线程数量 
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                
                // 再次获取ctl的值
                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类中
        Worker w = null;
        try {
            // 创建一个worker,将当初任务放进去
            w = new Worker(firstTask);
            
            //获取worker中的线程
            // 这里会调用ThreadFactory创建一个新的线程
            final Thread t = w.thread;
            if (t != null) {
                // workers是一个HashSet,操作需要加锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                
                try {
                    // 获取当前线程池状态
                    int rs = runStateOf(ctl.get());
                    
                    // 如果线程池状态为运行中
                    // 或者线程池状态为SHUTDOWN且firstTask为null,往线程池中添加线程池
                    // SHUTDOWN时不会添加新的任务,但是会执行阻塞队列中的任务
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 如果此时线程池是运行态,抛出异常
                        if (t.isAlive()) 
                            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;
        // newThread传的参数是Worker本身,而Worker实现了Runnable接口
        this.thread = getThreadFactory().newThread(this);
    }

    // 执行t.start()时,执行的是Worker的run()方法
    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 ((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置为空,线程可以自行调用getTask()方法从队列中获取任务
                    task = null;
                    // 记录当前worker执行多少次任务
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            // 线程回收的过程
            processWorkerExit(w, completedAbruptly);
        }
    }
    

   // 下面的方法很重要,是获取任务的方法
   private Runnable getTask() {
       // 超时标记,默认false,如果调用workerQueue.pull()超时则会置为true
       boolean timedOut = false; // Did the last poll() time out?

       for (;;) {
           // 获取当前线程池的状态
           int c = ctl.get();
           int rs = runStateOf(c);

           // Check if queue empty only if necessary.
           // 线程池状态大于SHUTDOWN,且workQueue中的任务为空
           // CAS减少工作线程数量,返回null,线程被回收
           if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
               decrementWorkerCount();
               return null;
           }

           // 获取线程池中有效线程数量
           int wc = workerCountOf(c);

           // Are workers subject to culling?
           // allowCoreThreadTimeOut默认为false,即默认不允许核心线程超时回收
           // 这里也说明在核心线程以外的线程都为“临时”线程,随时会被线程池回收
           boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;


           // 现并发时操作了setMaximumPoolSize方法,如果此时将最大线程数量调少了
           // 很可能会出现当前工作线程大于最大线程的情况
           // 这时就需要线程超时回收,以维持线程池最大线程小于maximumPoolSize
           
           // timed && timedOut 
           // 如果为true,表示当前操作需要进行超时控制,这里的timedOut为true,说明该线程已经从workQueue.poll()方法超时了

           if ((wc > maximumPoolSize || (timed && timedOut))
               && (wc > 1 || workQueue.isEmpty())) {
               // CAS线程池数量减一
               if (compareAndDecrementWorkerCount(c))
                   return null;
               // 循环重试
               continue;
           }

           try {
               // 阻塞超时获取任务,或者阻塞获取任务
               Runnable r = timed ?
                   workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                   workQueue.take();
                   
               if (r != null)
                   return r;
                   
               // 如果获取任务超时,将timeOut设置为true
               // 继续循环执行,如果碰巧开发者开启了allowCoreThreadTimeOut,那么该线程就满足超时回收了
               timedOut = true;
           } catch (InterruptedException retry) {
               timedOut = false;
           }
       }
   }

    // 如果任务没有执行,需要进行回滚
    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);
            decrementWorkerCount();
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

你可能感兴趣的:(JAVA,多线程)