<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    xylz,imxylz

    關(guān)注后端架構(gòu)、中間件、分布式和并發(fā)編程

       :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks

    [本文地址:http://www.tkk7.com/Files/xylz/Inside.Java.Concurrency_34.ThreadPool.part7_ThreadPoolExecutor_execute.pdf] 

     

    線程池任務(wù)執(zhí)行流程

    我們從一個(gè)API開始接觸Executor是如何處理任務(wù)隊(duì)列的。

    java.util.concurrent.Executor.execute(Runnable)

    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 RejectedExecutionHandler.

    線程池中所有任務(wù)執(zhí)行都依賴于此接口。這段話有以下幾個(gè)意思:

    1. 任務(wù)可能在將來某個(gè)時(shí)刻被執(zhí)行,有可能不是立即執(zhí)行。為什么這里有兩個(gè)“可能”?繼續(xù)往下面看。
    2. 任務(wù)可能在一個(gè)新的線程中執(zhí)行或者線程池中存在的一個(gè)線程中執(zhí)行。
    3. 任務(wù)無法被提交執(zhí)行有以下兩個(gè)原因:線程池已經(jīng)關(guān)閉或者線程池已經(jīng)達(dá)到了容量限制。
    4. 所有失敗的任務(wù)都將被“當(dāng)前”的任務(wù)拒絕策略RejectedExecutionHandler 處理。

    回答上面兩個(gè)“可能“。任務(wù)可能被執(zhí)行,那不可能的情況就是上面說的情況3;可能不是立即執(zhí)行,是因?yàn)槿蝿?wù)可能還在隊(duì)列中排隊(duì),因此還在等待分配線程執(zhí)行。了解完了字面上的問題,我們再來看具體的實(shí)現(xiàn)。

    public void execute(Runnable command) {
       
    if (command == null)
           
    throw new NullPointerException();
       
    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
           
    if (runState == RUNNING && workQueue.offer(command)) {
               
    if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
           
    else if (!addIfUnderMaximumPoolSize(command))
                reject(command);
    // is shutdown or saturated
        }
    }

    這一段代碼看起來挺簡單的,其實(shí)這就是線程池最重要的一部分,如果能夠完全理解這一塊,線程池還是挺容易的。整個(gè)執(zhí)行流程是這樣的:

    1. 如果任務(wù)command為空,則拋出空指針異常,返回。否則進(jìn)行2。
    2. 如果當(dāng)前線程池大小 大于或等于 核心線程池大小,進(jìn)行4。否則進(jìn)行3。
    3. 創(chuàng)建一個(gè)新工作隊(duì)列(線程,參考上一節(jié)),成功直接返回,失敗進(jìn)行4。
    4. 如果線程池正在運(yùn)行并且任務(wù)加入線程池隊(duì)列成功,進(jìn)行5,否則進(jìn)行7。
    5. 如果線程池已經(jīng)關(guān)閉或者線程池大小為0,進(jìn)行6,否則直接返回。
    6. 如果線程池已經(jīng)關(guān)閉則執(zhí)行拒絕策略返回,否則啟動(dòng)一個(gè)新線程來進(jìn)行執(zhí)行任務(wù),返回。
    7. 如果線程池大小 不大于 最大線程池?cái)?shù)量,則啟動(dòng)新線程來進(jìn)行執(zhí)行,否則進(jìn)行拒絕策略,結(jié)束。

    文字描述步驟不夠簡單?下面圖形詳細(xì)表述了此過程。

    Executor.execute

    老實(shí)說這個(gè)圖比上面步驟更難以理解,那么從何入手呢。

    流程的入口很簡單,我們就是要執(zhí)行一個(gè)任務(wù)(Runnable command),那么它的結(jié)束點(diǎn)在哪或者有哪幾個(gè)?

    根據(jù)左邊這個(gè)圖我們知道可能有以下幾種出口:

    (1)圖中的P1、P7,我們根據(jù)這條路徑可以看到,僅僅是將任務(wù)加入任務(wù)隊(duì)列(offer(command))了;

    (2)圖中的P3,這條路徑不將任務(wù)加入任務(wù)隊(duì)列,但是啟動(dòng)了一個(gè)新工作線程(Worker)進(jìn)行掃尾操作,用戶處理為空的任務(wù)隊(duì)列;

    (3)圖中的P4,這條路徑?jīng)]有將任務(wù)加入任務(wù)隊(duì)列,但是啟動(dòng)了一個(gè)新工作線程(Worker),并且工作現(xiàn)場的第一個(gè)任務(wù)就是當(dāng)前任務(wù);

    (4)圖中的P5、P6,這條路徑?jīng)]有將任務(wù)加入任務(wù)隊(duì)列,也沒有啟動(dòng)工作線程,僅僅是拋給了任務(wù)拒絕策略。P2是任務(wù)加入了任務(wù)隊(duì)列卻因?yàn)榫€程池已經(jīng)關(guān)閉于是又從任務(wù)隊(duì)列中刪除,并且拋給了拒絕策略。

    如果上面的解釋還不清楚,可以去研究下面兩段代碼:

    java.util.concurrent.ThreadPoolExecutor.addIfUnderCorePoolSize(Runnable)
    java.util.concurrent.ThreadPoolExecutor.addIfUnderMaximumPoolSize(Runnable)
    java.util.concurrent.ThreadPoolExecutor.ensureQueuedTaskHandled(Runnable)

    那么什么時(shí)候一個(gè)任務(wù)被立即執(zhí)行呢?

    在線程池運(yùn)行狀態(tài)下,如果線程池大小 小于 核心線程池大小或者線程池已滿(任務(wù)隊(duì)列已滿)并且線程池大小 小于 最大線程池大小(此時(shí)線程池大小 大于 核心線程池大小的),用程序描述為:

    runState == RUNNING && ( poolSize < corePoolSize || poolSize < maxnumPoolSize && workQueue.isFull())

    上面的條件就是一個(gè)任務(wù)能夠被立即執(zhí)行的條件。

    有了execute的基礎(chǔ),我們看看ExecutorService中的幾個(gè)submit方法的實(shí)現(xiàn)。

        public Future<?> submit(Runnable task) {
           
    if (task == null) throw new NullPointerException();
            RunnableFuture
    <Object> ftask = newTaskFor(task, null);
            execute(ftask);
           
    return ftask;
        }

       
    public <T> Future<T> submit(Runnable task, T result) {
           
    if (task == null) throw new NullPointerException();
            RunnableFuture
    <T> ftask = newTaskFor(task, result);
            execute(ftask);
           
    return ftask;
        }

       
    public <T> Future<T> submit(Callable<T> task) {
           
    if (task == null) throw new NullPointerException();
            RunnableFuture
    <T> ftask = newTaskFor(task);
            execute(ftask);
           
    return ftask;
        }

    很簡單,不是么?對于一個(gè)線程池來說復(fù)雜的地方也就在execute方法的執(zhí)行流程。在下一節(jié)中我們來討論下如何獲取任務(wù)的執(zhí)行結(jié)果,也就是Future類的使用和原理。

     



    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2011-02-11 23:48 imxylz 閱讀(11688) 評論(2)  編輯  收藏 所屬分類: J2EE 、Java Concurrency

    評論

    # re: 深入淺出 Java Concurrency (34): 線程池 part 7 線程池的實(shí)現(xiàn)及原理 (2) 2011-02-12 15:47 yeshucheng
    新年伊始,就看看到好東西,呵呵  回復(fù)  更多評論
      

    # re: 深入淺出 Java Concurrency (34): 線程池 part 7 線程池的實(shí)現(xiàn)及原理 (2) 2011-05-28 17:19 devoleper
    圖中的P3,這條路徑,為什么沒有將任務(wù)加入隊(duì)列呢?我看程序是加入了的呀?JDK1.5和1.6的實(shí)現(xiàn)好像不太一致...  回復(fù)  更多評論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 99爱免费观看视频在线| 亚洲欧洲国产综合AV无码久久| 中文字幕在线亚洲精品| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 日本无卡码免费一区二区三区| 97热久久免费频精品99 | 美景之屋4在线未删减免费| 欧美日韩亚洲精品| 国产成人亚洲毛片| 日韩在线一区二区三区免费视频| 污污视频免费观看网站| 一出一进一爽一粗一大视频免费的| 男人免费视频一区二区在线观看| 色多多A级毛片免费看| 国产日韩在线视频免费播放| 久久av免费天堂小草播放| 中文在线免费观看| 久久成人a毛片免费观看网站| 无码少妇精品一区二区免费动态| 99在线在线视频免费视频观看| 16女性下面无遮挡免费| 少妇高潮太爽了在线观看免费| 成人免费网站在线观看| 免费国产美女爽到喷出水来视频| 免费一级毛片不卡不收费| 国产亚洲美女精品久久久| 亚洲VA中文字幕无码一二三区 | 国产99视频免费精品是看6| 亚洲国产成人五月综合网 | 色窝窝免费一区二区三区| 国产成人精品免费视频软件| 亚洲AV蜜桃永久无码精品| 亚洲乱码国产乱码精品精| 久久久久久亚洲AV无码专区| 亚洲乱码在线卡一卡二卡新区| 国产精品亚洲天堂| 国产免费一区二区视频| AV大片在线无码永久免费| 国产在线98福利播放视频免费| 久久久久噜噜噜亚洲熟女综合| 久久精品亚洲综合|