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

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

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

    Picses' sky

    Picses' sky
    posts - 43, comments - 29, trackbacks - 0, articles - 24

    用Java線程獲取優(yōu)異性能(I)3

    Posted on 2007-07-18 13:09 Matthew Chen 閱讀(238) 評論(0)  編輯  收藏 所屬分類: Java MultiThread
    查詢活躍線程
    在有些情形下,你可能想了解在你的程序中哪些線程是激活的。Thread支持一對方法幫助你完成這個任務(wù): activeCount()和 enumerate(Thread [] thdarray)。但那些方法只工作在當(dāng)前線程的線程組中。換句話說,那些方法只識別屬于當(dāng)前線程的同一線程組的活躍線程。 (我將在以后的系列文章中討論線程組——一種組織機制。)
    靜態(tài)activeCount()方法返回在當(dāng)前線程的線程組中正在活躍運行的線程數(shù)量。一個程序利用這個方法的整數(shù)返回值設(shè)定一個Thread引用數(shù)組的大小。檢索那些引用,程序必須調(diào)用靜態(tài)enumerate(Thread [] thdarray)方法。這個方法的整數(shù)返回值確定Thread引用存貯在數(shù)組中的enumerate(Thread []thdarray)的總數(shù)。要看這些方法如何一起工作,請查看表6:
    表6. Census.java
    // Census.java
    class Census
    {
    public static void main (String [] args)
    {
    Thread [] threads = new Thread [Thread.activeCount ()];
    int n = Thread.enumerate (threads);
    for (int i = 0; i < n; i++)
    System.out.println (threads [i].toString ());
    }
    }
    在運行時,這個程序會產(chǎn)生如下的輸出:
    Thread[main,5,main]
    輸出顯示一個線程,開始線程正在運行。左邊的main表示線程的名稱。5顯示線程的優(yōu)先權(quán),右邊的main表示線程的線程組。你也許很失望不能在輸出中看到任何系統(tǒng)線程,比如垃圾收集器線程。那種限制由Thread的enumerate(Thread [] thdarray) 方法產(chǎn)生,它僅詢問當(dāng)前線程線程組的活躍線程。然而, ThreadGroup類包含多種enumerate()方法允許你捕獲對所有活躍線程的引用而不管線程組。在稍后的系列中,探討ThreadGroup時我將向你顯示如何列舉所有的引用。
    警告
    當(dāng)重申一個數(shù)組時不要依靠activeCount()的返回值。如果你這樣做了,你的程序?qū)⒚皵S出一個NullPointerException對象的風(fēng)險。為什么呢?在調(diào)用activeCount()和enumerate(Thread [] thdarray)之間,一個或更多線程可能結(jié)束。結(jié)果, enumerate(Thread [] thdarray)能夠復(fù)制少數(shù)線程引用進它的數(shù)組。因此,僅考慮將activeCount()的返回值作為數(shù)組可能大小的最大值。同樣,考慮將enumerate(Thread [] thdarray)的返回值作為在一個程序?qū)δ欠N方法調(diào)用時活躍線程的數(shù)目。
    反臭蟲
    如果你的程序出現(xiàn)故障并且你懷疑問題出在線程,通過調(diào)用Thread的dumpStack()和toString()方法你能夠了解到線程的更多細(xì)節(jié)。靜態(tài)dumpStack()方法提供一個new Exception ("Stack trace").printStackTrace ()的封裝,打印一個追蹤當(dāng)前線程的堆棧。toString()依據(jù)下面格式返回一個描述線程的名稱、優(yōu)先權(quán)和線程組的字符串: Thread[thread-name,priority,thread-group]. (在稍后的系列中你將學(xué)到更多關(guān)于優(yōu)先權(quán)的知識。)
    技巧
    在一些地方,這篇文章提到了當(dāng)前線程的概念。如果你需要訪問描述當(dāng)前線程的Thread對象,則調(diào)用Thread的靜態(tài)currentThread()方法。例:Thread current = Thread.currentThread ()。
    等級系統(tǒng)
    不是所有線程都被平等創(chuàng)建。它們被分成兩類:用戶和監(jiān)督。一個用戶線程執(zhí)行著對于程序用戶十分重要的工作,工作必須在程序結(jié)束前完成。相反,一個監(jiān)督線程執(zhí)行著后勤事務(wù)(比如垃圾收集)和其它可能不會對應(yīng)用程序的主要工作作出貢獻但對于應(yīng)用程序繼續(xù)它的主要工作卻非常必要的后臺任務(wù)。和用戶線程不一樣,監(jiān)督線程不需要在應(yīng)用程序結(jié)束前完成。當(dāng)一個應(yīng)用程序的開始線程(它是一個用戶線程)結(jié)束時,JVM檢查是否還有其它用戶線程正在運行。如果有,JVM就會阻止應(yīng)用程序結(jié)束。否則,JVM就會結(jié)束應(yīng)用程序而不管監(jiān)督線程是否正在運行。
    當(dāng)一個線程調(diào)用一個線程對象的start()方法時,新的已經(jīng)開始的線程就是一個用戶線程。那是缺省的。要建立一個線程作為監(jiān)督線程,程序必須在調(diào)用start()前調(diào)用Thread的一個帶布爾真值參數(shù)的setDaemon(boolean isDaemon)方法。稍后,你可以通過調(diào)用Thread的isDaemon()方法檢查一個線程是否是監(jiān)督線程。如果是監(jiān)督線程那個方法返回一個布爾真值。
    為了讓你試試用戶和監(jiān)督線程,我寫了一個UserDaemonThreadDemo:
    表7. UserDaemonThreadDemo.java
    // UserDaemonThreadDemo.java
    class UserDaemonThreadDemo
    {
    public static void main (String [] args)
    {
    if (args.length == 0)
    new MyThread ().start ();
    else
    {
    MyThread mt = new MyThread ();
    mt.setDaemon (true);
    mt.start ();
    }
    try
    {
    Thread.sleep (100);
    }
    catch (InterruptedException e)
    {
    }
    }
    }
    class MyThread extends Thread
    {
    public void run ()
    {
    System.out.println ("Daemon is " + isDaemon ());
    while (true);
    }
    }
    編譯了代碼后,通過Java2 SDK的java命令運行UserDaemonThreadDemo。如果你沒有使用命令行參數(shù)運行程序,例如java UserDaemonThreadDemo, new MyThread ().start ()執(zhí)行。這段代碼片斷開始一個在進入一個無限循環(huán)前打印Daemon is false的用戶線程。(你必須按Ctrl-C或一個等價于結(jié)束一個無限循環(huán)的組合按鍵。)因為新線程是一個用戶線程,應(yīng)用程序在開始線程結(jié)束后仍保持運行。然而,如果你指定了至少一個命令行參數(shù),例如java UserDaemonThreadDemo x,mt.setDaemon (true)執(zhí)行并且新線程將是一個監(jiān)督線程。結(jié)果,一旦開始線程從100毫秒休眠中醒來并結(jié)束,新的監(jiān)督線程也將結(jié)束。
    警告
    如果線程開始執(zhí)行后調(diào)用setDaemon(boolean isDaemon)方法,setDaemon(boolean isDaemon)方法將擲出一個IllegalThreadStateException對象。
    Runnable
    學(xué)習(xí)前面部份的例子后,你可能認(rèn)為引入多線程進入一個類總是要求你去擴展Thread并將你的子類重載Thread's run()方法。然而那并不總是一種選擇。Java對繼承的強制執(zhí)行禁止一個類擴展兩個或更多個超類。結(jié)果,如果一個類擴展了一個無線程類,那個類就不能擴展Thread. 假使限制,怎樣才可能將多線程引入一個已經(jīng)擴展了其它類的類?幸運的是, Java的設(shè)計者已經(jīng)意識到不可能創(chuàng)建Thread子類的情形總會發(fā)生的。這導(dǎo)致產(chǎn)生java.lang.Runnable接口和帶Runnable參數(shù)的Thread構(gòu)造器,如Thread(Runnable target)。
    Runnable接口聲明了一個單獨方法署名:void run()。這個署名和Thread的run()方法署名一樣并作為線程的執(zhí)行入口服務(wù)。因為Runnable是一個接口,任何類都能通過將一個implements子句包含進類頭和提供一個適當(dāng)?shù)膔un()方法實現(xiàn)接口。在執(zhí)行時間,程序代碼能從那個類創(chuàng)建一個對象或runnable并將runnable的引用傳遞給一個適當(dāng)?shù)腡hread構(gòu)造器。構(gòu)造器和Thread對象一起存貯這個引用并確保一個新線程在調(diào)用Thread對象的start()方法后調(diào)用runnable的run()方法。示范如表8:
    表8.RunnableDemo.java
    // RunnableDemo.java
    class RunnableDemo
    {
    public static void main (String [] args)
    {
    Rectangle r = new Rectangle (5, 6);
    r.draw ();
    //用隨機選擇的寬度和高度畫不同的長方形
    new Rectangle ();
    }
    }
    abstract class Shape
    {
    abstract void draw ();
    }
    class Rectangle extends Shape implements Runnable
    {
    private int w, h;
    Rectangle ()
    {
    //創(chuàng)建一個綁定這個runnable的新Thread對象并開始一個將調(diào)用這個runnable的
    //run()方法的線程
    new Thread (this).start ();
    }
    Rectangle (int w, int h)
    {
    if (w < 2)
    throw new IllegalArgumentException ("w value " + w + " < 2");
    if (h < 2)
    throw new IllegalArgumentException ("h value " + h + " < 2");
    this.w = w;
    this.h = h;
    }
    void draw ()
    {
    for (int c = 0; c < w; c++)
    System.out.print ('*');
    System.out.print ('\n');
    for (int r = 0; r < h - 2; r++)
    {
    System.out.print ('*');
    for (int c = 0; c < w - 2; c++)
    System.out.print (' ');
    System.out.print ('*');
    System.out.print ('\n');
    }
    for (int c = 0; c < w; c++)
    System.out.print ('*');
    System.out.print ('\n');
    }
    public void run ()
    {
    for (int i = 0; i < 20; i++)
    {
    w = rnd (30);
    if (w < 2)
    w += 2;
    h = rnd (10);
    if (h < 2)
    h += 2;
    draw ();
    }
    }
    int rnd (int limit)
    {
    //在0<=x<界限范圍內(nèi)返回一個隨機數(shù)字x
    return (int) (Math.random () * limit);
    }
    }
    RunnableDemo由類RunnableDemo,Shape和Rectangle組成。類RunnableDemo通過創(chuàng)建一個Rectangle對象驅(qū)動應(yīng)用程序—通過調(diào)用對象的draw()方法—和通過創(chuàng)建第二個什么都不做的Rectangle類。相反,Shape和Rectangle組成了一個基于shape層次的類。Shape是抽象的因為它提供一個抽象的draw()方法。各種shape類,比如Rectangle,擴展Shape和描述它們?nèi)绾萎嬎鼈冏约旱闹剌ddraw()。以后,我可能決定引入一些另外的shape類,創(chuàng)建一個Shape數(shù)組,通過調(diào)用Shape的draw()方法要求每一個Shape元素畫它自己。
    RunnableDemo 作為一個不帶多線程的簡單程序產(chǎn)生。后面我決定引入多線程到Rectangle,這樣我能夠用各種寬度和高度畫種種矩形。因為Rectangle擴展Shape (為了以后的多態(tài)性原因),我沒有其它選擇只有讓Rectangle實現(xiàn)Runnable。同樣,在Rectangle()構(gòu)造器內(nèi),我不得不將一個Rectangle runnable綁定到一個新的Thread對象并調(diào)用Thread的start()方法開始一個新的線程調(diào)用Rectangle的run()方法畫矩形。
    因為包括在這篇文章中的RunnableDemo的新輸出太長了,我建議你自己編譯并運行程序。
    技巧
    當(dāng)你面對一個類不是能擴展Thread就是能實現(xiàn)Runnable的情形時,你將選擇哪種方法?如果這個類已經(jīng)擴展了其它類,你必須實現(xiàn)Runnable。然而,如果這個類沒有擴展其它類,考慮一下類的名稱。名稱將暗示這個類的對象不是積極的就是消極的。例如,名稱Ticker暗示它的對象是積極的。因此,Ticker類將擴展Thread,并且Ticker對象將被作為專門的Thread對象。相反,Rectangle暗示消極對象—Rectangle對象對于它們自己什么也不做。因此,Rectangle類將實現(xiàn)Runnable,并且Rectangle 對象將使用Thread對象(為了測試或其它意圖)代替成為專門的Thread對象。
    回顧
    用戶期望程序達到優(yōu)異的性能。一種辦法是用線程完成那些任務(wù)。一個線程是一條程序代碼的獨立執(zhí)行通道。線程有益于基于GUI的程序,因為它們允許那些程序當(dāng)執(zhí)行其它任務(wù)時仍對用戶保持響應(yīng)。另外,帶線程的程序比它們沒帶線程的副本程序完成的快。這對于運行在多處理器機器上的情形尤其明顯,在這里每一個線程有它自己的處理器。Thread和Thread子類對象描述了線程并與那些實體相關(guān)。對于那些不能擴展Thread的類,你必須創(chuàng)建一個runnable以利用多線程的優(yōu)勢。
    主站蜘蛛池模板: 亚洲人成电影在线观看青青| 老司机精品视频免费| 亚洲欧洲在线观看| 美女免费视频一区二区| 亚洲中文字幕无码一久久区| 免费福利在线播放| 日本黄页网址在线看免费不卡| 亚洲国产精品VA在线观看麻豆| 午夜无遮挡羞羞漫画免费| 成在线人视频免费视频| 亚洲一区二区三区高清不卡| 亚洲国产一区二区视频网站| 日韩电影免费在线观看网址| 亚洲国产精品久久久久久| 成人永久福利免费观看| 亚洲欧美日韩中文无线码| 国产aⅴ无码专区亚洲av| 免费观看大片毛片| 国产精品区免费视频| 小说区亚洲自拍另类| 亚洲精品欧洲精品| 国产91精品一区二区麻豆亚洲 | 国产免费观看黄AV片| 亚洲成人免费在线| xxxxxx日本处大片免费看| 亚洲乱码无码永久不卡在线| 免费看又爽又黄禁片视频1000| 久久精品乱子伦免费| 黄色一级毛片免费看| 亚洲视频无码高清在线| 亚洲国产一区二区a毛片| 亚洲日韩国产成网在线观看| 毛片免费观看的视频在线| 久久精品人成免费| 亚洲码和欧洲码一码二码三码 | 无码毛片一区二区三区视频免费播放| 亚洲福利视频网站| 亚洲A∨无码无在线观看| 国产精品亚洲高清一区二区 | 亚洲1234区乱码| 亚洲精品高清视频|