1. 程式人生 > >執行緒池細節詳解ThreadPoolExecutor

執行緒池細節詳解ThreadPoolExecutor

關於執行緒池的幾個引數的含義,我們就不多說了,下面我們通過原始碼看下這幾個引數分別是在什麼地方使用到的:

核心池大小與最大池大小是在執行任務的時候用到的,這裡我們不多說。

當執行緒池中沒有任務,執行緒池就會維持核心池大小的執行緒,這個原始碼如下:

當執行緒進來會先被封裝成一個Worker類,這個類實現了Runnable介面,如下:

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }

實際上,執行緒池建立的執行緒,是先執行的這個Worker類的run方法,然後才執行Runnable類的run方法,即為封裝了一層,如下:
Runnable task = w.firstTask;
task.run();
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) {

runWorker中有一個getTask()方法,我們著重來看這個方法,裡面就有為什麼核心執行緒數的執行緒可以一直存在的祕密:
    private Runnable getTask() {
        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.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c)) return null; continue; } try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }

上面可以看到,如果當前執行緒數(wc>corePoolSize)的話,則執行阻塞佇列的poll方法,否則執行take()方法,而poll方法中,傳入了一個keepAliveTIme的引數,此時空閒執行緒會等keepalive的時間,如果取不到資料則返回空,當前執行緒走完結束,如果執行take()方法,則會一直阻塞,知道取到資料,這就是為什麼核心執行緒池一直存在的原因。

同時我們還看到一個allowCoreThreadTimeOut引數,這個引數預設值是false,如果不想讓核心執行緒存在也可以主動將此引數設定為true。

另外還有一個可以說下的就i是ThreadFactory,它建立執行緒的方式跟我們平時建立執行緒用的方式是一樣的:

this.thread = getThreadFactory().newThread(this);
        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;
        }
也就是new了一個執行緒這樣而已。ThreadFactory只是建立執行緒用的,線上程建立好後,就跟ThreadFactory完全沒有關係了。