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

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

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

    FORTUNE

    THE WAY TO THE MASTER...
    posts - 49, comments - 18, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    中斷JAVA線程

    Posted on 2006-04-12 13:36 fortune 閱讀(587) 評論(0)  編輯  收藏 所屬分類: java技術
    在JAVA中,通過其對線程類的內嵌支持,編程人員編寫多線程程序是很簡易的。然而,在編程人員面前,多線程呈現出了一組新的難題,如果沒有被恰當的解決,將導致意外的行為以及細微的、難以發現的錯誤。在本篇文章中,我們針對這些難題之一:如何中斷一個正在運行的線程。?

    背景
    中斷(Interrupt)一個線程意味著在該線程完成任務之前停止其正在進行的一切,有效地中止其當前的操作。線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決于這個程序。

    雖然初次看來它可能顯得簡單,但是,你必須進行一些預警以實現期望的結果。你最好還是牢記以下的幾點告誡。

    首先,忘掉Thread.stop方法。雖然它確實停止了一個正在運行的線程,然而,這種方法是不安全也是不受提倡的,這意味著,在未來的JAVA版本中,它將不復存在。

    一些輕率的家伙可能被另一種方法Thread.interrupt所迷惑。盡管,其名稱似乎在暗示著什么,然而,這種方法并不會中斷一個正在運行的線程(待會將進一步說明),正如Listing?A中描述的那樣。它創建了一個線程,并且試圖使用Thread.interrupt方法停止該線程。Thread.sleep()方法的調用,為線程的初始化和中止提供了充裕的時間。線程本身并不參與任何有用的操作。

    Listing?A
    class?Example1?extends?Thread?{

    ??public?static?void?main(?String?args[]?)?throws?Exception?{

    ????Example1?thread?=?new?Example1();

    ???System.out.println(?"Starting?thread..."?);

    ???thread.start();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Interrupting?thread..."?);

    ???thread.interrupt();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Stopping?application..."?);

    ???System.exit(?0?);

    ??}


    如果你運行了Listing?A中的代碼,你將在控制臺看到以下輸出:

    Starting?thread...

    Thread?is?running...

    Thread?is?running...

    Thread?is?running...

    Interrupting?thread...

    Thread?is?running...

    Thread?is?running...

    Thread?is?running...

    Stopping?application...

    甚至,在Thread.interrupt()被調用后,線程仍然繼續運行了一段時間。

    真正地中斷一個線程

    中斷線程最好的,最受推薦的方式是,使用共享變量(shared?variable)發出信號,告訴線程必須停止正在運行的任務。線程必須周期性的核查這一變量(尤其在冗余操作期間),然后有秩序地中止任務。Listing?B描述了這一方式。

    Listing?B
    class?Example2?extends?Thread?{

    ??volatile?boolean?stop?=?false;

    ??public?static?void?main(?String?args[]?)?throws?Exception?{

    ????Example2?thread?=?new?Example2();

    ???System.out.println(?"Starting?thread..."?);

    ???thread.start();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Asking?thread?to?stop..."?);

    ???thread.stop?=?true;

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Stopping?application..."?);

    ???System.exit(?0?);

    ??}

    ??public?void?run()?{

    ????while?(?!stop?)?{

    ?????System.out.println(?"Thread?is?running..."?);

    ??????long?time?=?System.currentTimeMillis();

    ??????while?(?(System.currentTimeMillis()-time?<?1000)?&&?(!stop)?)?{

    ??????}

    ????}

    ???System.out.println(?"Thread?exiting?under?request..."?);

    ??}

    }

    ?


    運行Listing?B中的代碼將產生如下輸出(注意線程是如何有秩序的退出的)

    Starting?thread...

    Thread?is?running...

    Thread?is?running...

    Thread?is?running...

    Asking?thread?to?stop...

    Thread?exiting?under?request...

    Stopping?application...

    雖然該方法要求一些編碼,但并不難實現。同時,它給予線程機會進行必要的清理工作,這在任何一個多線程應用程序中都是絕對需要的。請確認將共享變量定義成volatile?類型或將對它的一切訪問封入同步的塊/方法(synchronized?blocks/methods)中。

    到目前為止一切順利!但是,當線程等待某些事件發生而被阻塞,又會發生什么?當然,如果線程被阻塞,它便不能核查共享變量,也就不能停止。這在許多情況下會發生,例如調用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,這里僅舉出一些。

    他們都可能永久的阻塞線程。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使用某種機制使得線程更早地退出被阻塞的狀態。

    很不幸運,不存在這樣一種機制對所有的情況都適用,但是,根據情況不同卻可以使用特定的技術。在下面的環節,我將解答一下最普遍的例子。

    使用Thread.interrupt()中斷線程
    正如Listing?A中所描述的,Thread.interrupt()方法不會中斷一個正在運行的線程。這一方法實際上完成的是,在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態。更確切的說,如果線程被Object.wait,?Thread.join和Thread.sleep三種方法之一阻塞,那么,它將接收到一個中斷異常(InterruptedException),從而提早地終結被阻塞狀態。

    因此,如果線程被上述幾種方法阻塞,正確的停止線程方式是設置共享變量,并調用interrupt()(注意變量應該先設置)。如果線程沒有被阻塞,這時調用interrupt()將不起作用;否則,線程就將得到異常(該線程必須事先預備好處理此狀況),接著逃離阻塞狀態。在任何一種情況中,最后線程都將檢查共享變量然后再停止。Listing?C這個示例描述了該技術。

    Listing?C
    class?Example3?extends?Thread?{

    ??volatile?boolean?stop?=?false;

    ??public?static?void?main(?String?args[]?)?throws?Exception?{

    ???Example3?thread?=?new?Example3();

    ???System.out.println(?"Starting?thread..."?);

    ???thread.start();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Asking?thread?to?stop..."?);

    ???thread.stop?=?true;

    ???thread.interrupt();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Stopping?application..."?);

    ???System.exit(?0?);

    ??}

    ??public?void?run()?{

    ????while?(?!stop?)?{

    ?????System.out.println(?"Thread?running..."?);

    ??????try?{

    ??????Thread.sleep(?1000?);

    ??????}?catch?(?InterruptedException?e?)?{

    ??????System.out.println(?"Thread?interrupted..."?);

    ??????}

    ????}

    ???System.out.println(?"Thread?exiting?under?request..."?);

    ??}

    }

    一旦Listing?C中的Thread.interrupt()被調用,線程便收到一個異常,于是逃離了阻塞狀態并確定應該停止。運行以上代碼將得到下面的輸出:

    Starting?thread...

    Thread?running...

    Thread?running...

    Thread?running...

    Asking?thread?to?stop...

    Thread?interrupted...

    Thread?exiting?under?request...

    Stopping?application...


    中斷I/O操作
    然而,如果線程在I/O操作進行時被阻塞,又會如何?I/O操作可以阻塞線程一段相當長的時間,特別是牽扯到網絡應用時。例如,服務器可能需要等待一個請求(request),又或者,一個網絡應用程序可能要等待遠端主機的響應。

    如果你正使用通道(channels)(這是在Java?1.4中引入的新的I/O?API),那么被阻塞的線程將收到一個ClosedByInterruptException異常。如果情況是這樣,其代碼的邏輯和第三個例子中的是一樣的,只是異常不同而已。

    但是,你可能正使用Java1.0之前就存在的傳統的I/O,因為新的I/O是最近才引入,而且要求更多的工作。既然這樣,Thread.interrupt()將不起作用,因為線程將不會退出被阻塞狀態。Listing?D描述了這一行為。盡管interrupt()被調用,線程也不會退出被阻塞狀態

    Listing?D
    import?java.io.*;

    class?Example4?extends?Thread?{

    ??public?static?void?main(?String?args[]?)?throws?Exception?{

    ????Example4?thread?=?new?Example4();

    ???System.out.println(?"Starting?thread..."?);

    ???thread.start();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Interrupting?thread..."?);

    ???thread.interrupt();

    ???Thread.sleep(?3000?);

    ???System.out.println(?"Stopping?application..."?);

    ???System.exit(?0?);

    ??}

    ??public?void?run()?{

    ???ServerSocket?socket;

    ????try?{

    ??????socket?=?new?ServerSocket(7856);

    ????}?catch?(?IOException?e?)?{

    ?????System.out.println(?"Could?not?create?the?socket..."?);

    ??????return;

    ????}

    ????while?(?true?)?{

    ?????System.out.println(?"Waiting?for?connection..."?);

    ??????try?{

    ???????Socket?sock?=?socket.accept();

    ??????}?catch?(?IOException?e?)?{

    ??????System.out.println(?"accept()?failed?or?interrupted..."?);

    ??????}

    ????}

    ??}

    }


    很幸運,Java平臺為這種情形提供了一項解決方案,即調用阻塞該線程的套接字的close()方法。在這種情形下,如果線程被I/O操作阻塞,該線程將接收到一個SocketException異常,這與使用interrupt()方法引起一個InterruptedException異常被拋出非常相似。

    唯一要說明的是,必須存在socket的引用(reference),只有這樣close()方法才能被調用。這意味著socket對象必須被共享。Listing?E描述了這一情形。運行邏輯和以前的示例是相同的。

    Listing?E
    import?java.net.*;
    import?java.io.*;
    class?Example5?extends?Thread?{
    ??volatile?boolean?stop?=?false;
    ??volatile?ServerSocket?socket;
    ??public?static?void?main(?String?args[]?)?throws?Exception?{
    ????Example5?thread?=?new?Example5();
    ???System.out.println(?"Starting?thread..."?);
    ???thread.start();
    ???Thread.sleep(?3000?);
    ???System.out.println(?"Asking?thread?to?stop..."?);
    ???thread.stop?=?true;
    ???thread.socket.close();
    ???Thread.sleep(?3000?);
    ???System.out.println(?"Stopping?application..."?);
    ???System.exit(?0?);
    ??}
    ??public?void?run()?{
    ????try?{
    ??????socket?=?new?ServerSocket(7856);
    ????}?catch?(?IOException?e?)?{
    ?????System.out.println(?"Could?not?create?the?socket..."?);
    ??????return;
    ????}
    ????while?(?!stop?)?{
    ?????System.out.println(?"Waiting?for?connection..."?);
    ??????try?{
    ???????Socket?sock?=?socket.accept();
    ??????}?catch?(?IOException?e?)?{
    ??????System.out.println(?"accept()?failed?or?interrupted..."?);
    ??????}
    ????}
    ???System.out.println(?"Thread?exiting?under?request..."?);
    ??}
    }
    以下是運行Listing?E中代碼后的輸出:

    Starting?thread...

    Waiting?for?connection...

    Asking?thread?to?stop...

    accept()?failed?or?interrupted...

    Thread?exiting?under?request...

    Stopping?application...

    多線程是一個強大的工具,然而它正呈現出一系列難題。其中之一是如何中斷一個正在運行的線程。如果恰當地實現,使用上述技術中斷線程將比使用Java平臺上已經提供的內嵌操作更為簡單。
    主站蜘蛛池模板: 中文日本免费高清| 国产成人亚洲精品无码AV大片| 中文字幕a∨在线乱码免费看| 国产美女a做受大片免费| 亚洲大尺度无码无码专线一区| 成年大片免费视频| 亚洲av成人一区二区三区观看在线| 女人18一级毛片免费观看| 亚洲日韩国产AV无码无码精品| 国产精品久久久久免费a∨| 亚洲永久网址在线观看| 日本免费网站观看| 人妻巨大乳hd免费看| 免费va在线观看| 久久久精品国产亚洲成人满18免费网站| 国产偷国产偷亚洲高清日韩| 成年免费a级毛片免费看无码| 久久精品国产亚洲AV麻豆~| 亚洲一区二区三区免费观看| 亚洲国产视频久久| 亚洲а∨天堂久久精品| 免费无码又爽又刺激高潮软件| 亚洲精品综合一二三区在线| 嫖丰满老熟妇AAAA片免费看| 亚洲爆乳无码专区www| 免费午夜爽爽爽WWW视频十八禁 | 亚州免费一级毛片| 亚洲精品国产第一综合99久久| 亚洲第一区精品观看| 无码午夜成人1000部免费视频| 亚洲国产日韩在线| 亚洲国产电影av在线网址| 另类免费视频一区二区在线观看| 亚洲三级视频在线| 亚洲精品第一国产综合境外资源 | 精品在线免费视频| 亚洲精品自产拍在线观看| 91在线视频免费播放| 免费无码午夜福利片69| 亚洲人成电影在在线观看网色| 国产精品免费视频播放器|