ThreadPoolExecutor 简单学习

在这里插入图片描述

Executors 其实是个工 具 类,里面提 供了好多静态
方法,这些方法根据用 户 选择返回不同的线程池实例 。 ThreadPoo!Executor 继承了
Abs tractExecutorService ,成员变量 ct! 是一个 Integer 的原子变量 ,用 来记录线程池状态和
线程池中线程个数,类似于 ReentrantReadWriteLock 使用 一个变量来保存两种信息。

结构

在这里插入图片描述

public class ThreadPoolExecutor extends AbstractExecutorService {
//( 高3位)用来表示线程池状态, (低29位)用来表示线程个数
//默认是RUNNING状态,线程个数为 0
 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
 //线程个数掩码位数,并不是所有平台 的工的类型都是32位的,所以准确地说, 是具体平台 下 Integer的二进制位数- 3后的剩余位数所表示的数才是线程的个数 
    private static final int COUNT_BITS = Integer.SIZE - 3;
    //线程最大个数(低29位) 00011111111111111111111111111111
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
	//线程池状态 :
    // runState is stored in the high-order bits
    //(高 3位) : 11100000000000000000000000000000
    private static final int RUNNING    = -1 << COUNT_BITS;
    //( 高3位) : 00000000000000000000000000000000
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    //(高 3位) : 00100000000000000000000000000000
    private static final int STOP       =  1 << COUNT_BITS;
    //( 高 3位) : 01000000000000000000000000000000
    private static final int TIDYING    =  2 << COUNT_BITS;
    //( 高 3位) : 01100000000000000000000000000000
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
    //获取高 3位(运行状态)
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    ///获取低29位(线程个数)
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    //计算ctl新值(线斗呈状态与线程个数 )
    private static int ctlOf(int rs, int wc) { return rs | wc; }
    ...

线程池状态含义如下

  • RUNNING : 接受新任务并且处理阻塞队列里的任务 。
  • SHUTDOWN :拒绝新任务但是处理阻塞队列里的任务 。
  • 拒绝新任务并且抛弃阻塞队列里 的任务 ,同时会中断正在处理的任务。
  • TIDYING : 所有任务都执行完(包含阻塞队列里面的任务)后当前线程池活动线程
    数为 0 , 将要调用 terminated 方法 。
    TERMINATED : 终止状态 。 terminated 方法调用完成 以后的状态.

线程池状态转换列举如下

  • RUNNING -> SHUTDOWN : 显式调用 shutdown() 方法 , 或者隐式调用了 finalize()
    方法里面的 shutdown() 方法 。
  • RUNNING 或 SHUTDOWN)-> STOP : 显式调用 shutdownNow() 方法时.
  • SHUTDOWN -> TIDYING : 当线程池和任务队列都为空时 。
  • STOP -> TIDYING : 当线程池为空时 。
  • TIDYING > TERMINATED> 当 terminated() hook 方法执行完成时 。

线程池的参数

  • corePoo lSize :线程池核心线程个数
  • workQueue :用于保存等待执行的任务的阻 塞 队列,比如基于数组的有界ArrayBlock ingQueue 、基于链表的无界 LinkedBlockingQueue 、最多只有一个元素的同步队列 SynchronousQueue 及优先级队列 PriorityBlockingQueue 等
  • maximunPoolSize : 线程池最大线程数量
  • ThreadFactory :创建线程的工厂
  • RejectedExecutionHandler :饱和策略 , 当 队列满并且线程个数达到 maximunPoolSize后采取 的策略, 比如 AbortPolicy (抛出异常〉、 CallerRunsPolicy (使用调用者所在线程来运行任务) 、 DiscardOldestPolicy (调用 poll 丢弃一个任务,执行当前任务)及 DiscardPolicy (默默丢弃,不抛出异常〉
  • keeyAliveTime :存活时间 。 如果当前线程池中的线程数量比核心线程数量多 ,并且是闲置状态, 则这些闲置的线程能存活的最大时间
  • TimeUnit : 存活时间的时间单位 。

线程池类型

  • newFixedThreadPool :创建一个核心线程个数和最大线程个数都为 nThreads 的线程池,并且阻塞 队列长度为 Integer.MAX_VALUE.keeyAliveTime =0,说明只要线程个数比核心线程个数多并且当前空闲则 回收.
 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }
  • newSingleThreadExecutor:创建一个核心线程个数和最大线程个数都为 1 的线程池 ,并且阻塞队列长度为 Integer.MAX_VALUE 。 keeyA liveTime=O 说明只要线程个数比核心线程个数多并且当前空闲 则 回收。
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

  • newCachedThreadPoo: 创建一个按需创建线程的线程池,初始线程个数为 0 , 最多线程个数为 Integer.MAX_VALUE,并且阻塞队列为同步队列 。 keeyAliveTime=60说明只要当前线程在 60s 内空闲则回收。这个类型的特殊之处在于 , 加入同步队列
    的任务会被马上执行,同步队列里面最多只有一个任务。

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

其中 mainLock 是独占锁 , 用来控制新增 Worker
线程操作的原子性 。 termination 是该锁对应 的 条件队列 , 在线程调用 awaitTermination 时
用 来存放阻塞 的线程 。
Worker 继承 AQS 和 Runnable 接口 , 是具体承载 任务的 对象。 Worker 继 承 了 AQS,
自 己实现 了简单不可重入独占锁 , 其中 state=O 表示锁未被获取状态 , state=l 表示锁 己经
被获取的状态, state二l 是创建 Worker 时默认的状态 ,创建时状态设置为一l 是为了避免
该线程在运行 runWorker() 方法前被 中 断 ,下面会具体讲解。其 中变量 自rstTask 记录该工
作线程执行的第一个任务 , thread 是具体执行任务的线程。
DefaultThreadFactory 是 线程工厂 , newThread 方 法是对 线程 的 一 个修饰 。 其中
poo!Number 是个静态 的 原子变量 , 用来统计线程工厂 的个数 , threadNumber 用 来记录每
个线程工厂创建了多少线程 , 这两个值也作为线程池和线程的名称的一部分

public void execute(Runnable command)

execute 方法的作用是 提交任务 command 到线程池进行执 行。

在这里插入图片描述

ThreadPoo!Executor 的实现实际是一个生产消费模型, 当用户添加
任务到线程池时相当于生产者生产元素, workers 线程工作集中的线程直接执行任务或者
从任务队列里面获取任务时则相当于消费者消费元素。


public void execute(Runnable command) {
//1 如采任务为 null ,则抛出 NPE异常
        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.
         */
        //2 获取当前线程池的状态+线程个数变量组合值
        int c = ctl.get();
        //3 当前线程池中线程个数是否 小于corePoolSize ,小于则开启新线程运行
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //4. 如果线程池处于RUNNING状态,则添加任务到阻塞队 91]
        if (isRunning(c) && workQueue.offer(command)) {
         //4.1 二次检查
            int recheck = ctl.get();
           //4.2 如果当前线程;也状态不是RUNNING!il1J从队§1]中删除任务,并执行拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
                //4.3 否则如果当前线程池为空 , 则添加一个线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //如果队列满 , 如j 新增线程 , 新增失败则执行拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }
  • addWorker
private boolean addWorker(Runnable firstTask, boolean core) {
//第一部分双重循环的目的是通过 CAS 操作增加线程数:
        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
            }
        }
	//第二部分主要是把并发安全的任务添加到 workers 里面,并且启动任务执行  到这里说明CAS成功了
        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;
    }

第一部分双重循环的目的是通过 CAS 操作增加线程数:
第二部分主要是把并发安全的任务添加到 workers 里面,并且启动任务执行

工作线程 Worker 的执行


 Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker   在调用 runWorker前禁止中 断
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);  //创建一个新的线程
        }

在构造函数内 首先设置 Worker 的状态为 一i ,这 是为了避免当前 Worker 在调用
rnnWorker 方法前被中断(当其他线程调用了线程池的 shutdownNow 时-,如果 Worker 状
态 >=O 则会中|新该线程) 。这里设置了线程的状态为 - 1 ,所以该线程就不会被中断了 。 在
如下 rnnWorker 代码中,运行代码( 9 ) 时会调用 unlock 方法,该方法把 status 设置为了。,
所以这时候调用 shutdownNow 会中断 Worker 线程。

拒绝策略

不能有无限大小的缓存队列,因为如果有大量的任务进来,会导致内存的激增,如果一直激增而没有释放,会导致内存异常。
所以当发现负载到了一定的程度后,应该选择丢弃一些任务,而不是放在内存中,看着内存被耗掉,丢弃的时候希望把这些丢掉的任务(比如数量,具体是那些)记录下来。
在这里插入图片描述

  • AbortPolicy :默认策略
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

这个策略是如果不能执行了,就会抛出异常,并且将具体的任务信息打印出啦

  • CallerRunsPolicy
   public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

if (!e.isShutdown()) {
r.run();
}

如果线程池还活着,就让调用者执行这个任务,这个类本身自己不做处理。

  • DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

这个策略是如果不执行了,就直接丢弃掉,设么也不做。

  • DiscardOldestPolicy
 public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

这个策略是 将队列中最老的丢弃掉。

ThreadFactory 线程工厂

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-";
        }

//创建新的线程 能够在创造Thread的时候给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;
        }
    }

猜你喜欢

转载自blog.csdn.net/ko0491/article/details/90926790
今日推荐