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

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

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

    拾貝殼

    走過的路
    隨筆 - 39, 文章 - 1, 評(píng)論 - 14, 引用 - 0
    數(shù)據(jù)加載中……

    一個(gè)簡(jiǎn)單的ThreadPool分析

    一個(gè)簡(jiǎn)單的ThreadPool
    ? 原文來自http://www.informit.com/articles/printerfriendly.asp?p=30483&r1=1&rl=1
    ? 項(xiàng)目是多線程的,所以引入了線程池這個(gè)東西。池子是個(gè)老美寫的。在項(xiàng)目中表現(xiàn)的還不錯(cuò)。所以把它摘出來,介紹給以后或許需要用到它的同行們。
    ? 關(guān)于為什么要采用ThreadPool,原文已經(jīng)提到了:創(chuàng)建一個(gè)線程是需要開銷的;如果線程數(shù)量過大的話,cpu就會(huì)浪費(fèi)很大的精力做線程切換。
    ? ThreadPool的實(shí)現(xiàn)過程就是對(duì)WorkerThread的同步和通信的管理過程。
    ? 我們來看代碼。
    ? 首先,在ThreadPool構(gòu)造的時(shí)候,創(chuàng)建10個(gè)WorkerThread(size=10)并讓他們運(yùn)行。每個(gè)WorkerThread線程都有個(gè)ThreadPool的引用,用于查詢ThreadPool的狀態(tài)和獲得同步鎖.WorkerThread運(yùn)行以后,循環(huán)調(diào)用ThreadPool的方法進(jìn)行查詢,如果沒有發(fā)現(xiàn)任務(wù),ThreadPool告訴正在查詢的線程進(jìn)入休眠狀態(tài),WorkerThread釋放對(duì)查詢方法的鎖定.這樣在還沒有任務(wù)的時(shí)候,所有的10個(gè)WorkerThread都會(huì)進(jìn)入休眠狀態(tài),進(jìn)入等待ThreadPool對(duì)象的等待鎖定池,只有ThreadPool對(duì)象發(fā)出notify方法(或notifyAll)后WorkerThread線程才進(jìn)入對(duì)象鎖定池準(zhǔn)備獲得對(duì)象鎖進(jìn)入運(yùn)行狀態(tài)。
    代碼片斷:
    while ( !assignments.iterator().hasNext() )
    ??? wait();
    如果你有jprofile或者其他的觀察線程的工具,你可以看到有10個(gè)線程都在休眠狀態(tài).
    ? 接著,我們向ThreadPool中加入任務(wù),這些任務(wù)都實(shí)現(xiàn)了Runnable的run方法.(至于為什么把任務(wù)都做成Runnable,譯者至今也有些疑問?預(yù)定俗成?TimerTask也是實(shí)現(xiàn)自Runnable,弄得初學(xué)者經(jīng)常把真正運(yùn)行的線程搞混).ThreadPool每assign一個(gè)任務(wù),就會(huì)發(fā)出一條消息,通知它的等待鎖定池中的線程.各個(gè)線程以搶占的方式獲得對(duì)象鎖,然后很順利的獲得一條任務(wù).并把此任務(wù)從ThreadPool里面刪除.沒有搶到的繼續(xù)等待.
    Runnable r = (Runnable)assignments.iterator().next();
    ?? assignments.remove(r);
    WorkerThread從ThreadPool那里獲得了任務(wù),繼續(xù)向下執(zhí)行。
    target = owner.getAssignment();
    ?? if (target!=null) {
    ??? target.run();?????
    ??? owner.done.workerEnd();
    ?? }
    記住,這里調(diào)用的是target.run();而不是調(diào)用的線程的start()方法。也就是說在這里表現(xiàn)出的WorkerThread和task之間的關(guān)系僅僅是簡(jiǎn)單的方法調(diào)用的關(guān)系,并沒有額外產(chǎn)生新線程。(這就是我上面納悶為什么大家都實(shí)現(xiàn)Runnable來做task的原因)
    ?大家可能注意到,WorkerThread并沒有對(duì)異常作處理。而我們知道發(fā)生在線程上的異常會(huì)導(dǎo)致線程死亡。解決的辦法有2中,一種是通過threadpool的管理來重新激起一個(gè)線程,一種是把異常在線程之內(nèi)消滅。在項(xiàng)目中,我采用的是第二中,因此這個(gè)片斷改稱這樣:
    if (target!=null) {
    ? try{
    ??? target.run();?????
    ?? }
    ? catch(Throwable t){
    ?.......
    ?? }
    ??? owner.done.workerEnd();
    }
    在WorkerThread完成一個(gè)task以后,繼續(xù)循環(huán)作同樣的流程.
    在這個(gè)ThreadPool的實(shí)現(xiàn)里面,Jeff Heaton用了一個(gè)Done類來觀察WorkerThread的執(zhí)行情況.和ThreadPoool的等待鎖定池不同,Done的等待鎖定池里面放的是初始化ThreadPool的線程(可能是你的主線程),我們叫他母線程.
    ? 在給出的測(cè)試?yán)又?母線程在調(diào)用complete()方法后進(jìn)入休眠(在監(jiān)視中等待),一開始是waitBegin()讓他休眠,在assign加入task以后,waitDone()方法讓他休眠.在WorkerThread完成一個(gè)task以后,通知waitDone()起來重新檢查activeThreads的數(shù)值.若不為0,繼續(xù)睡覺.若為0,那么母線程走完,死亡(這個(gè)時(shí)候該做的task已經(jīng)做完了).母線程走完,ThreadPool還存在嗎?答案是存在,因?yàn)閃orkerThread還沒有消亡,他們?cè)诘却乱慌蝿?wù),他們有ThreadPool的引用,保證ThreadPool依然存在.大家或許已經(jīng)明白Done這個(gè)類的作用了.
    ? 細(xì)心的讀者或許會(huì)發(fā)現(xiàn),發(fā)生在Done實(shí)例上的notify()并不是像ThreadPool上的notify()那樣每次都能完成一項(xiàng)工作.比如除了第一個(gè)被assign的task,其他的task在assign進(jìn)去的時(shí)候,發(fā)出的notify()對(duì)于waitDone()來說是句"狼來了".
    ?最后在ThreadPool需要被清理得時(shí)候,使每一個(gè)WorkerThread中斷(這個(gè)時(shí)候或許所有的WorkerThread都在休眠)并銷毀.記住這里也是一個(gè)異步的過程.等到每一個(gè)WorkerThread都已經(jīng)銷毀,finalize()的方法體走完.ThreadPool被銷毀.
    ?for (int i=0;i<threads.length;i++) {
    ?? threads[i].interrupt();
    ?? done.workerBegin();
    ?? threads[i].destroy();
    ? }
    ? done.waitDone();
    為什么有句done.workerBegin();?不明白.
    參考文章:
    http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39276905-3800066897t-20000560c

    posted on 2006-07-16 20:07 binge 閱讀(7186) 評(píng)論(1)  編輯  收藏 所屬分類: J2SE

    評(píng)論

    # re: 一個(gè)簡(jiǎn)單的ThreadPool分析  回復(fù)  更多評(píng)論   

    糾正一個(gè)明顯的錯(cuò)誤:

    ----------
    關(guān)于為什么要采用ThreadPool,原文已經(jīng)提到了:創(chuàng)建一個(gè)線程是需要開銷的,如果線程數(shù)量過大的話,cpu就會(huì)浪費(fèi)很大的精力做線程切換。
    ----------

    線程池的目的不是reuse,而是overload shield.這是初涉多線程編程的人經(jīng)常會(huì)犯的概念性錯(cuò)誤,也是對(duì)于線程池功能最常見的誤解

    況且,你指出的原文已經(jīng)說的很明白了,你似乎沒有理解原文的意思
    原文:
    Why a Thread Pool?
    When programming the crawler in the previous section, a problem that would soon present itself is the number of threads to use. A crawler may have to visit tens of thousands of pages, and you certainly do not want to create tens of thousands of threads because each thread imposes a certain amount of overhead. If the number of threads grows too large, the computer will be spending all of its time switching between threads, rather than just executing them.

    To solve this problem, you must create a thread pool. The thread pool is given some fixed number of threads to use. The thread pool will assign its tasks to each of these threads. As the threads finish with old tasks, new ones are assigned. This causes the program to use a fixed number of threads, not to be continually creating new threads.

    -----------------

    再說,這篇文章太老了,說java沒有提供內(nèi)建的線程池實(shí)現(xiàn),java5.0已經(jīng)提供了內(nèi)建的線程池
    2006-07-18 02:59 | fisher

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 亚洲精品乱码久久久久蜜桃| 亚洲乱码一区av春药高潮| 暖暖免费中文在线日本| 日韩成人免费在线| 在线观看亚洲免费| 免费人成网站在线播放| 免费一级全黄少妇性色生活片| 免费不卡中文字幕在线| 免费人人潮人人爽一区二区| 亚洲熟妇少妇任你躁在线观看无码| 西西人体大胆免费视频| 亚洲中久无码不卡永久在线观看| www在线观看播放免费视频日本| 在线日韩日本国产亚洲| 国产一区二区免费| 亚洲综合在线成人一区| 成视频年人黄网站免费视频| 亚洲色大成网站www尤物| 免费国产人做人视频在线观看| 国产精品福利片免费看| 久久亚洲AV无码精品色午夜麻| 91精品全国免费观看含羞草| 国产精品亚洲综合五月天| 亚洲?V无码成人精品区日韩| 国产一级a毛一级a看免费人娇| 亚洲三级电影网址| 在线免费一区二区| 青青操视频在线免费观看| 亚洲字幕在线观看| 免费h黄肉动漫在线观看| 182tv免费视频在线观看| 亚洲综合久久一本伊伊区| 免费在线不卡视频| 日韩人妻无码精品久久免费一| 亚洲字幕在线观看| 亚洲综合精品网站在线观看| 最近2019年免费中文字幕高清 | 视频一区在线免费观看| 久久亚洲精品国产精品黑人| 性色av无码免费一区二区三区| 一个人看的www免费高清|