• 使用Executor框架创建线程池


    Executor框架

    Executor类:在java.util.concurrent类中,是JDK并发包的核心类。

    ThreadPoolExecutor: 线程池。

    Excutors: 线程池工厂,通过Executor可以创建一个特定功能的线程池。

    一)、Executor框架的类的关系

    Executor, ExecutorService, AbstractExcutorService, ThreadPoolExecutor,Executors

    Eecutor类:

    接口,只有一个execute()方法:

    public interface Executor {
        void execute(Runnable command);
    }
    

    ExecutorService extends Executor类:

    接口,ExecutorService extends Executor,主要方法如下:

       //关闭线程池
       void shutdown();
       boolean isShutdown();
       List<Runnable> shutdownNow();
       boolean isTerminated();
       <T> Future<T> submit(Callable<T> task);
       //提交线程任务,并返回执行结果
       Future<?> submit(Runnable task);
    

    AbstractExecutorService类:

    abstract class AbstractExecutorService implements ExecutorService,主要实现submit()方法。

        public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Void> ftask = newTaskFor(task, null);
           //内部还是调用了execute()
            execute(ftask);
            return ftask;
        }
    
    

    ThreadPoolExecutor类:

    class ThreadPoolExecutor extends AbstractExecutorService

    二)、线程池的状态:

    参考:https://blog.csdn.net/nobody_1/article/details/98335594

    运行(RUNNING): 线程池接收新任务,并处理队列中的任务。

    关机(SHUTDOWN): 线程池不接受新的任务,但接收队列的任务,调用

    ​ shutdown()后线程的状态。

    停止(STOP): 线程池不接受新的任务,也不处理队列中的任务,并中断执行中

    ​ 的任务,调用shutdownNow()线程的状态。

    清理(tidying): 线程池所有任务已经终止,workCount(当前线程个数)为0,过渡

    ​ 到清理状态的线程将运行terminated()的子方法 。

    终止(terminated): terminate()方法结束后线程的状态。

        //线程池的容量11111111111111111111111111111: 29个1
       private static final int CAPACITY   = (1 << COUNT_BITS)      - 1; 
        //运行状态,-2^29,10000000000000000000000000000,1个1,29个0
        private static final int RUNNING    = -1 << COUNT_BITS;     // 关机状态 0
        private static final int SHUTDOWN   =  0 << COUNT_BITS;
        // 停止 2^29
        private static final int STOP       =  1 << COUNT_BITS;
         // 清理状态 2 * 2^29
        private static final int TIDYING    =  2 << COUNT_BITS;
         // 终止状态 3 * 2^29
        private static final int TERMINATED =  3 << COUNT_BITS;
    

    注:使用线程的高三位代表线程的状态,使用低29位代表工作线程的个数。

    三)、获取池状态

    private static int runStateOf(int c){ 
      //获得高3位
      return c & ~ CAPACITY;
    }
    

    四)、获得工作线程数

    private static int workerCountOf(int c){
        return c & Capacity;
    }
    

    五)、使用AtomicInteger变量来表示线程池状态和工作线程数量

    //刚开始初始化时,线程的状态默认为RUNNING, 工作线程个数为0
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0))
        
    //rs:运行状态(runState), wc:工作线程数 (workCount)
     private static int ctlOf(int rs, int wc) {
        return rs | wc; 
    }
    

    使用ctl可以获取线程状态和工作线程数

    int c = ctl.get();
    
    runStateOf(c): 获取运行状态
    
    workerCountOf(c): 获取工作线程数
    

    六)、线程池对象:ThreadPoolExecutor

    1)、主要属性:

      
    //线程池的锁
    private final ReentrantLock mainLock = new ReentrantLock();
    
    //线程池中重用线程对象
    private final HashSet<Worker> workers = new HashSet<Worker>();
    
    //最大线程个数
    private int largestPoolSize;
    //当线程超过最大核心线程数时的阻塞队列
    private final BlockingQueue<Runnable> workQueue;
    
    //实时监控线程池的状态和工作线程的个数
     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;
    

    2)、构造方法:

        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
            if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null)
                throw new NullPointerException();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    

    3)、参数信息:

    corePoolSize: 指定了线程池中的线程数量

    maximumPoolSize: 指定线程池中的最大线程数量

    KeepAliveTime: 超过corePoolSize后增加的线程的空闲时间,超过这个时间线程

    ​ 未使用,则销毁该线程。

    unit: KeepAliveTime的单位

    workQueue: 任务队列,被提交但尚未被执行的任务

    threadFactory: 线程工厂,一般用于创建线程。

    handle: 拒绝策略,当任务太多,来不及处理,如何拒绝任务。

    七)、workeQueue:等待队列

    1).SynchronousQueue:直接提交的队列

    ​ 特点: 没有容量,每一个插入操作都要等待一个相应的删除操作。

    ​ 作用:应用于new CacheThreadPool线程池的workerQueue队列,不保存任务,

    ​ 总 是将任务提交给线程执行,如果没有空闲的进程,则尝试创建新的线

    ​ 程,如果进程的数量达到最大值,则执行拒绝策略。

    注: 一直创建新的线程,直至线程数到达maximumPoolSize,执行拒绝策略。

    2).ArrayBlockingQueue: 有界队列

    ​ 特点:使用构造函数,指定队列的最大容量

    public ArrayBlockingQueue(int capacity){
        
    }
    

    ​ 作用:当有新的任务要执行时,如果线程池的实际线程数小于coreSize,则会优先

    ​ 创建新的线程,若大于corePoolSize,则会将新任务加入等待队列,若等

    ​ 待队已满,在总线程数不大于maximumPoolSize的前提下创建线程,当总

    ​ 线程 数超过maxmmumPoolSize时执行拒绝策略。

    ** 注:**当线程数小于coreSize时,创建新的线程,大于coreSize时,将任务加入

    ​ 等待 队列,直至等待队列加满,在总线程数不超过maximumPoolSize的前

    ​ 提下创建线程,否则,执行拒绝策略。

    3).LinkedBlockingQueue: 无界队列

    ​ 特点:除非资源耗尽,否则无界队列不存在任务入队失败的情况。

    ​ 作用:系统有任务时,若总的线程数小于corePoolSize则创建新的线程,否则,

    ​ 则将线程添加至等待队列中,无界队列保持快速增长,直至耗尽系统内

    ​ 存。

    ​ ** 注:** 当线程数小于corePoolSize时,创建新的线程,大于corePoolSize时,将

    ​ 任务加入等待队列中,直至耗尽系统内存,线程的个数一直维护在

    ​ corePoolSize 。

    4).PriorityBlockingQueue: 优先任务队列

    ​ 特点:控制任务的执行先后顺序,是一个特殊的无界队列

    作用:根据任务自身的优先级先后执行

    八)、handler,JDK内置的四种拒绝策略

    1). AbortPolicy: 直接抛出异常,阻滞系统工作

    2).CallerRunsPolicy: 在调用者线程中运行当前被丢弃任务

    3).DiscardOledstPolicy: 丢弃最老的一个请求,即即将被执行的一个任务,并尝试

    ​ 再次提交当前任务。

    4).DiscardPolicy: 丢弃无法处理的任务,不予任何处理。

    注:若要自定义拒绝策略,实现RejecteExecutionHandler接口,实现

    ​ rejectedExecution方法。

    九)、execute()方法

    步骤:

    1)、参数传递,得到一个任务对象

    2)、判断

    //Runnable command 当前要执行的线程任务
    public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            //获取定前线程池的状态
            int c = ctl.get();
            //判断当前主线程数量是否超过corePoolSize,如果不超过,则新建一个线程对象
            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);
        }
    
    
    //线程池中添加新的线程,并执行线程任务
    private boolean addWorker(Runnable firstTask, boolean core) {
            retry:
            for (;;) {
                int c = ctl.get();
                //获取运行状态
                int rs = runStateOf(c);
    
                // Check if queue empty only if necessary.
                //如若当前处于关闭、清理、终止,任务队列不为空时返回false,因为,队列不为空,说明线程个数达到核心线程的个数,不能创建新的线程值,返回false
                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;
        }
    

    七)、Executors:线程池工厂

    继承ThreadPoolExecutor,可以取得一个特定功能的线程池

    构造方法:

    注:所有的线程池的构造,其内部最终都是调用了ThreadPoolExecutor的构造方法

    1)、newFixThreadPool(int nThread): 创建一个固定大小的线程池

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

    2)、newSingleThreadExecutor(): 返回一个只有一个线程的线程池

        public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }
    
    1. 、new CacheThreadPool(): 返回一个可以根据实际情况调整线程数量的线程池
        public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    
    

    4)、new SingleThreadSchaduleExecutor(): 返回一个ScheduleExecutor对象,

    retry: 标记循环位置,在continur和break后面加retry表示循环直接跳出到retry标

    ​ 记处。

       public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
            return new DelegatedScheduledExecutorService
                (new ScheduledThreadPoolExecutor(1));
        }
    
    
    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    如何优雅的使用mybatis
    Spring Data JPA、MyBatis还有Hibernate有什么区别
    微服务RPC框架选美
    微服务 Rpc和Rest协议
    开源PaaS工具CloudFoundry落地阿里云
    JS中的位置和宽度:clientWidth、offsetWidth、scrollWidth等区别
    vue cli3.X项目打包
    前端实现文件下载功能
    vue elementui 页面监控form表单数据变化
    vue 刮刮乐功能实现
  • 原文地址:https://www.cnblogs.com/Auge/p/11736389.html
Copyright © 2020-2023  润新知