• Java基础之-ExecutorService(线程池)


    今天看的源码是线程池的部分,记录下,源码看的jdk8的。

    主要是讲述下,创建线程池的过程,以及绘制的原理图片。

    从线程池的execute代码开始入手

    【源码一】

    java.util.concurrent.ThreadPoolExecutor.execute(Runnable command)

    /**
         * Executes the given task sometime in the future.  The task
         * may execute in a new thread or in an existing pooled thread.
         *
         * If the task cannot be submitted for execution, either because this
         * executor has been shutdown or because its capacity has been reached,
         * the task is handled by the current {@code RejectedExecutionHandler}.
         *
         * @param command the task to execute
         * @throws RejectedExecutionException at discretion of
         *         {@code RejectedExecutionHandler}, if the task
         *         cannot be accepted for execution
         * @throws NullPointerException if {@code command} is null
         */
        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);
        }

    一句 int c = ctl.get()直接整懵逼了,于是开始翻到开头看

    java.util.concurrent.ThreadPoolExecutor文件开头:

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

    这个部分稍微有点儿难理解看了半天(还是字节处理的基础没打牢)。  (友情提示:这里理解的时候请先看下源码反码补码的知识)

    (按32位系统介绍)

    CONT_BITS = Integer.SIZE -3 = 32 - 3 = 29

    CAPACITY = (1 << CONT_BITS) -1  = 1<<29 -1  = 2的29次方 -1 = 536870911

    -1二进制:11111111111111111111111111111111

    0二进制:0

    1二进制:1

    2二进制:10

    3二进制:11

    RUNNING        = -1  二进制:1111 1111 1111 1111 1111 1111 1111 1111  << 29 = 1110 0000 0000 0000 0000 0000 0000 0000    

    SHUTDOWN       =  0  二进制:0000 0000 0000 0000 0000 0000 0000 0000  << 29 = 0000 0000 0000 0000 0000 0000 0000 0000  

    STOP           =  1  二进制:1000 0000 0000 0000 0000 0000 0000 0000  << 29 =   10 0000 0000 0000 0000 0000 0000 0000  

    TIDYING        =  2  二进制:1000 0000 0000 0000 0000 0000 0000 0000  << 29 =  100 0000 0000 0000 0000 0000 0000 0000  

    TERMINATED     =  3  二进制:1100 0000 0000 0000 0000 0000 0000 0000  << 29 =  110 0000 0000 0000 0000 0000 0000 0000

     

    CAPACITY=2的29次方 -1 =   二进制:0010 0000 0000 0000 0000 0000 0000 0000 -1 = 0001 1111 1111 1111 1111 1111 1111 1111  

    大家看最后一排,相当于capacity 是 0001*后边全是1, 而状态就是111*,000*,001*,010*,011*

    知道这个之后大家看源码下边的三个方法:

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

    这样了之后,大家看代码第一句,初始状态下:

    ctl这个原子变量的值:ctlof(RUNNING, 0),ctlof方法里是: RUNNING | 0,结果还是RUNNING本身。

    runStateOf 是 值与~CAPACITY与操作,也就是c & (非0001 1111 1111 1111 1111 1111 1111 1111)

    即:c与1110 0000 0000 0000 0000 0000 0000 0000的与,在与操作下有一个是0,结果就是0了,~CAPACITY后29位全是0,其实也就是前三位的运算。这是算状态

    workerCountOf 是 值与CAPACITY的与操作,也就是c与0001 1111 1111 1111 1111 1111 1111 1111的与,CAPACITY前三位全是0,其实就是跟后29位的运算。这是容量的运算

    这样大家看懂了吧,其实状态就是32位字节里,前3位表示状态,后29位是容量。

    用二进制表示,这样容量就是0到2的29次方。前三位永远留下来,是状态位。

       * The runState provides the main lifecycle control, taking on values:

         *

         *   RUNNING:  Accept new tasks and process queued tasks

         *   SHUTDOWN: Don't accept new tasks, but process queued tasks

         *   STOP:     Don't accept new tasks, don't process queued tasks,

         *             and interrupt in-progress tasks

         *   TIDYING:  All tasks have terminated, workerCount is zero,

         *             the thread transitioning to state TIDYING

         *             will run the terminated() hook method

         *   TERMINATED: terminated() has completed

         *

     

    RUNNING: 接收新的任务并且执行列表中的任务

    SHUTDOWN:不接受新的任务,但是执行列表中的任务

    STOP:不接受新的任务,不处理列表中的任务,并且终端正在执行的任务

    TIDYING:所有任务终止,执行线程是0,线程过度到

    讲到这儿,我们就能继续下面的故事了。

    下边我们分解【源码一】的部分,其实注释就是按照【源码一】的步骤写的,下边这部分适合注释:

    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.

    英文就不翻译了,写的言简意赅我没四级都能看懂这里就不赘述了。

    int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }

    其实就是看下当前处理任务的总量是否大于corePoolSize,而corePoolSize是线程池线程的数量,这里只要正在处理的任务数量不超过用来处理任务的线程数量,那么就创建一个,来处理。

     

  • 相关阅读:
    oracle数据类型
    hive的union,hive连接查询的优化,mapjoin的设置参数
    hive分隔符
    hive load数据到表的方式
    hive的常用命令操作与数据类型以及hive的严格模式
    hadoop fs 与 dfs 的区别
    pl/sql程序语法,存储过程, orcle服务
    mysql连接启动
    HTTP协议
    php6
  • 原文地址:https://www.cnblogs.com/aquariusm/p/7277440.html
Copyright © 2020-2023  润新知