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

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

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

    隨筆-128  評論-55  文章-5  trackbacks-0

    http://sunnylocus.iteye.com/blog/538282

    當(dāng)一個單線程化的控制臺程序因為未捕獲的異常終止的時候,程序停止運行,并生了棧追蹤,這與典型的程序輸出不同,當(dāng)一個程序發(fā)生了異常說明有不穩(wěn)定的因素存在。如果并發(fā)程序中線程失敗就沒那么容易發(fā)現(xiàn)了。棧追蹤可能會從控制臺輸出,但是沒有人會去一直在看控制臺,并且,當(dāng)線程失敗的時候,應(yīng)用程序可能看起來仍在工作。就象程序能跑在50個線程池上,也能夠跑在49個線程的線程池上,區(qū)別在于50個人干的活要比49個人干的活要多的多。

      導(dǎo)致線程死亡的的最主要的原因是RuntimeException。因為這些異常表明一個程序錯誤或者不可修復(fù)的錯誤,它們不著順著棧的調(diào)用傳遞,此時,默認(rèn)的行為是在控制臺打印棧追蹤的信息,并終止線程。

      我們舉個例子,將奴隸主比作是你寫的程序,奴隸比作是線程。假如你是奴隸主,你手下有5名奴隸,你分派他們一項任務(wù)去將不斷開采來的石頭搬到某個地方。如果中途有奴隸逃跑,那么搬運石頭的效率就會下降,如果你沒有措施發(fā)現(xiàn)奴隸逃跑,最后連一個奴隸也沒有了,沒有人再去搬石頭了。當(dāng)你發(fā)現(xiàn)程序有問題,比如程序剛啟動的時候處理速度很快,以后越跑越慢,最后完全停止了,你可能不知道問題出在哪兒,其實這都是因為線程泄露引起的。想解決奴隸逃跑問題,不難,給每個奴隸戴上個報警器,一逃跑報警器就給你發(fā)信息,告訴哪個奴隸,因為什么原因逃跑了,可以根據(jù)需要再增加一名奴隸,讓搬石頭的奴隸數(shù)量始終維持在5名或著將信息記錄到文件,便于分析導(dǎo)致線程泄露的原意改進程序。ok,我們用代碼說話

    1、定義好報警器

    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.bill99.thread.test;   
    2.   
    3. import java.lang.Thread.UncaughtExceptionHandler;   
    4.   
    5. //將泄露的線程信息輸出到控制臺   
    6. public class UEHLogger implements UncaughtExceptionHandler {   
    7.     public void uncaughtException(Thread t, Throwable e) {   
    8.         System.out.println(String.format("不好了,有奴隸逃跑了!奴隸姓名:%1$s,編號:%2$s,逃跑原因:%3$s", t.getName(),t.getId(),e.getMessage()));   
    9.         System.out.println("還剩"+HelotPool.helotPool.getActiveCount()+"個奴隸");   
    10.     }   
    11. }  

      

    2、我們先建立一個奴隸工廠,每名奴隸出工廠的時候都會有一個報警器

        

    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.bill99.thread.test;   
    2.   
    3. import java.util.concurrent.ThreadFactory;   
    4. //奴隸制造工廠   
    5. public class HelotFactory implements ThreadFactory {   
    6.     private volatile int helotId=0;//奴隸編號   
    7.     //產(chǎn)生一個新奴隸   
    8.     public Thread newThread(Runnable r) {   
    9.         Thread helotThread = new Thread(r);   
    10.         helotThread.setName("helot-Thread-"+gethelotId());//設(shè)置奴隸姓名   
    11.         helotThread.setUncaughtExceptionHandler(new UEHLogger());//UEHLogger就是報警器   
    12.         return helotThread;   
    13.     }   
    14.     private int gethelotId(){   
    15.         return ++helotId;   
    16.     }   
    17. }  

     3、奴隸逃跑測試,看看是否會觸發(fā)報警器

    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.bill99.thread.test;   
    2.   
    3. import java.util.concurrent.ThreadFactory;   
    4. //奴隸逃跑測試   
    5. public class HelotEscapeTest {   
    6.     private ThreadFactory factory = new HelotFactory();   
    7.     private Thread helotThread = null;   
    8.        
    9.     public HelotEscapeTest(){   
    10.         Runnable task = new Runnable() {   
    11.             int stoneNum=1;   
    12.             public void run() {   
    13.                 while(!Thread.interrupted()){   
    14.                     System.out.println(helotThread.getName()+" 搬第"+stoneNum+"塊石頭..");   
    15.                     stoneNum++;   
    16.                     try{   
    17.                         Thread.sleep(500);   
    18.                     } catch(InterruptedException e){e.printStackTrace();}   
    19.                     if(stoneNum>100){   
    20.                         throw new RuntimeException("又餓又累沒力氣搬石頭了");   
    21.                     }   
    22.                 }   
    23.             }   
    24.         };   
    25.         helotThread = factory.newThread(task);   
    26.     }   
    27.     //開始干活   
    28.     public void startWork(){   
    29.         helotThread.start();   
    30.     }   
    31.     public static void main(String[] args) {   
    32.         HelotEscapeTest test = new HelotEscapeTest();   
    33.         test.startWork();   
    34.     }   
    35. }  

     運行程序后,奴隸在搬完100塊石頭后不干了,報警器給出提示信息

       不好了,有奴隸逃跑了!奴隸姓名:helot-Thread-1,編號:7,逃跑原因:又餓又累沒力氣搬石頭了

    這樣我就能找出線程泄露的原因了。如果在線程池中發(fā)生了泄露是否也能記錄?

    4、奴隸池測試

    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.bill99.thread.test;   
    2.   
    3. import java.util.Random;   
    4. import java.util.concurrent.BlockingQueue;   
    5. import java.util.concurrent.LinkedBlockingQueue;   
    6. import java.util.concurrent.ThreadFactory;   
    7. import java.util.concurrent.ThreadPoolExecutor;   
    8. import java.util.concurrent.TimeUnit;   
    9.   
    10. public class HelotPoolTest {   
    11.        
    12.     public static ThreadPoolExecutor helotPool;   
    13.     private int helotNum= 5;  //奴隸數(shù)   
    14.     private Random random = new Random(100);   
    15.        
    16.     private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();   
    17.        
    18.     public HelotPoolTest() {   
    19.         ThreadFactory factory = new HelotFactory();   
    20.         helotPool = new ThreadPoolExecutor( helotNum,helotNum,1000,TimeUnit.SECONDS,queue,factory);   
    21.     }   
    22.     //分配任務(wù)   
    23.     public void assignTask(){   
    24.         final int MAX=100;   
    25.         final int MIN=10;   
    26.         Runnable task = null;   
    27.         for(int j=0;j<20;j++){   
    28.             task = new Runnable() {   
    29.                 int stoneNum = random.nextInt(MAX - MIN + 1) + MIN;// 生成10~100范圍的隨機數(shù)   
    30.                 public void run() {   
    31.                     for (int i = 1; i <= stoneNum; i++) {   
    32.                         System.out.println(Thread.currentThread().getName() + " 搬完"+ i + "塊石頭");   
    33.                         if (i == 60) {   
    34.                             throw new RuntimeException("搬完第60塊石頭不干了");   
    35.                         }   
    36.                         try{   
    37.                             Thread.sleep(100);//休息下   
    38.                         }catch(InterruptedException e){e.printStackTrace();}   
    39.                     }   
    40.                 }   
    41.             };   
    42.             queue.add(task);   
    43.         }   
    44.     }   
    45.     //開始干活   
    46.     public void startWork(){   
    47.         helotPool.prestartAllCoreThreads();   
    48.     }   
    49.     public static void main(String[] args) {   
    50.         HelotPoolTest pool = new HelotPoolTest();   
    51.         pool.assignTask();   
    52.         pool.startWork();   
    53.     }   
    54. }  

     程序啟動,用Jprofiler監(jiān)控,剛啟動時會有5名奴隸干活不一會就會有線程退出,最后5個線程全部退,報警器對每個線程退出都能記錄到導(dǎo)致線程退出的原因。標(biāo)準(zhǔn)的Executor實現(xiàn)是:

    在需求不高時回收空閑的線程,在需求增加時添加新的線程,如果任務(wù)拋出了異常,就會用一個全新的工作線程取代出錯的那個。

    JDK文檔是這么說的,不過通過Jprofiler監(jiān)控只有在5名奴隸全部逃跑,沒人干活的時候ThreadPoolExecutor才會生成一個新線程繼續(xù)搬石頭,并不是只要一個線程退出就會馬上生成新線程去代替。



    Author: orangelizq
    email: orangelizq@163.com

    歡迎大家訪問我的個人網(wǎng)站 萌萌的IT人
    posted on 2013-05-29 16:43 桔子汁 閱讀(600) 評論(0)  編輯  收藏 所屬分類: J2SE
    主站蜘蛛池模板: 久久精品国产亚洲夜色AV网站| 亚洲高清无在码在线电影不卡| 国产做国产爱免费视频| 亚洲最大福利视频网站| 夭天干天天做天天免费看| 一级毛片**免费看试看20分钟| 久久久久亚洲精品天堂| 日本一区免费电影| 久久久久久影院久久久久免费精品国产小说 | 国产免费的野战视频| 精品国产亚洲AV麻豆| 亚洲va在线va天堂va不卡下载| 妞干网手机免费视频| 中文字幕无码日韩专区免费| 亚洲中文无码永久免| 国产精品久久久亚洲| 国产美女无遮挡免费视频网站| 国产精成人品日日拍夜夜免费| 亚洲丰满熟女一区二区哦| 国产成A人亚洲精V品无码| 日本不卡免费新一二三区| 50岁老女人的毛片免费观看| 高清免费久久午夜精品| 中文字幕亚洲男人的天堂网络| 亚洲综合网站色欲色欲| 男女交性永久免费视频播放| 99国产精品免费视频观看| 亚洲精品国产日韩无码AV永久免费网 | 国产免费av一区二区三区| 亚洲欧洲免费视频| 久香草视频在线观看免费| 亚洲熟女www一区二区三区| 中文字幕亚洲综合久久| 亚洲中文字幕无码久久综合网| 精品免费国产一区二区| 中文字幕影片免费在线观看| 日韩精品在线免费观看| 大妹子影视剧在线观看全集免费| 亚洲欧洲AV无码专区| 亚洲一卡2卡3卡4卡国产网站| 亚洲av无码不卡一区二区三区 |