1. 程式人生 > >Java基礎之-ExecutorService(線程池)

Java基礎之-ExecutorService(線程池)

color cor ack 基礎 and 運算 margin ast 繪制

今天看的源碼是線程池的部分,記錄下,源碼看的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次方。前三位永遠留下來,是狀態位。

講到這兒,我們就能繼續下面的故事了。

Java基礎之-ExecutorService(線程池)