日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

停止(终止)线程

發布時間:2025/3/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 停止(终止)线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

停止線程是在多線程開發中很重要的技術點,掌握此技術可以對線程的停止進行有效的處理。停止線程在 Java 語言中并不像 break 語句那樣干脆,需要一些技巧性的處理。

使用 Java 內置支持多線程的類設計多線程應用是很常見的事情,然而,多線程給開發人員帶來了一些新的挑戰,如果處理不好就會導致超出預期的行為并且難以定位錯誤。

本節將討論如何更好地停止一個線程。停止一個線程意味著在線程處理完任務之前停掉正在做的操作,也就是放棄當前的操作。雖然這看起來非常簡單,但是必須做好防范措施,以便達到預期的效果。

停止一個線程可以使用 Threadstop() 方法,但最好不用它。雖然它確實可以停止一個正在運行的線程,但是這個方法是不安全的,而且已被棄用作廢了,在將來的 Java 版本中,這個方法將不可用或不被支持。

大多數停止一個線程的操作使用 Thread.interrupt() 方法,盡管方法的名稱是“停止,中止”的意思,但這個方法不會終止一個正在運行的線程,還需要加入一個判斷才可以完成線程的停止。關于此知識點在后面有專門的章節進行介紹。

在 Java 中有以下 3 種方法可以終止正在運行的線程:

  • 使用退出標識,使線程正常退出,也就是當 run() 方法完成后線程終止。
  • 使用 stop() 方法強行終止線程,但是不推薦使用這個方法,因為 stop() 和 suspend() 及 resume()一樣,都是作廢過期的方法,使用它們可能產生不可預料的結果。
  • 使用 interrupt() 方法中斷線程。
  • 停止不了的線程

    interrupt() 方法的作用是用來停止線程,但 intermpt() 方法的使用效果并不像循環結構中 break 語句那樣,可以馬上停止循環。調用 intermpt() 方法僅僅是在當前線程中打了一個停止的標記,并不是真的停止線程。

    例 1
    下面通過一個案例演示 interrupt() 方法停止線程的用法。案例用到的線程非常簡單,僅僅是實現輸出從 1~10000 的整數,代碼如下:

    public class MyThread extends Thread {public void run(){super.run();for(int i=0;i<10000;i++){System.out.println("i="+(i+1));}}}

    在調用 intermpt() 方法停止 MyThread 線程之前,首先進行了一個 100 毫秒的休眠。主線程的代碼如下:

    public class Test {public static void main(String[] args) {try {MyThread thread=new MyThread();//創建MyThread線程實例thread.start();//啟動線程Thread.sleep(100);thread.interrupt();//停止線程} catch (InterruptedException e) {System.out.println("main catch");e.printStackTrace();}//延時100毫秒} }

    主線程的運行結果如下所示。從中可以看到,雖然在延時 100 毫秒后調用 intermpt() 方法停止了 thread 線程,但是該線程仍然執行完成輸出 10000 行信息。

    i=1 i=2 ... i=9999 i=10000

    判斷線程是不是停止狀態

    在介紹如何停止線程的知識點前,先來看一下如何判斷線程的狀態是不是停止的。在 Java 的 SDK 中,Thread.java 類里提供了兩種方法。

  • this.interrupted():測試當前線程是否已經中斷。
  • this.islnterrupted():測試線程是否已經中斷。
  • 那么這兩個方法有什么區別呢?先來看看 this.intermpted() 方法的解釋:測試當前線程是否已經中斷,當前線程是指運行 this.interrupted() 方法的線程。為了對此方法有更深入的了解,下面通過一個案例進行說明。

    例 2
    假設 MyThread 線程類的代碼如下:

    public class MyThread extends Thread {@Override public void run(){ super.run(); for(int i=0;i<10000;i++){ System.out.println("i="+(i+1)); } } }

    主線程的代碼如下:

    public class Test {public static void main(String[] args) {try {MyThread thread=new MyThread();//創建MyThread線程實例thread.start();//啟動線程Thread.sleep(100); //延時100毫秒thread.interrupt();//停止線程System.out.println("是否停止1?="+thread.interrupted());System.out.println("是否停止2?="+thread.interrupted());} catch (InterruptedException e) {System.out.println("main catch");e.printStackTrace();}System.out.println("end!");} }

    程序運行后的結果如下所示。

    i=1 i=2 ... i=9999 i=10000 是否停止1=false 是否停止2=false end!

    在主線程中是在 thread 對象上調用以下代碼來停止 thread 對象所代表的線程。

    thread.interrupt();

    后面又使用以下代碼來判斷 thread 對象所代表的線程是否停止。

    System.out.println("是否停止 1 ? ="+thread.interrupted()); System.out.println("是否停止 2 ? ="+thread.interrupted());

    從控制臺打印的結果來看,線程并未停止,這也就證明了 interrupted() 方法的解釋:測試當前線程是否已經中斷。這個“當前線程”是 main,它從未中斷過,所以打印的結果是兩個 false。

    那么如何使 main 線程產生中斷效果呢?再來看一下如下的代碼:

    public static void main(String[] args) {Thread.currentThread().interrupt();System.out.println(" 是否停止 1 ? ="+Thread.interrupted());System.out.println(" 是否停止 2 ? ="+Thread.interrupted());System.out.println("end!"); }

    程序運行后的結果如下所示。

    是否停止 1 ? =true 是否停止 2 ? =false end!

    從上述的結果來看,intermpted() 方法的確用來判斷出當前線程是不是停止狀態。但為什么第二個布爾值是 false 呢?查看一下官方幫助文檔中對 interrupted() 方法的解釋如下(斜體顯示):
    測試當前線程是否已經中斷。線程的中斷狀態由該方法清除。換句話說,如果連續兩次調用該方法,則第二次調用將返回 false(在第一次調用已清除了其中斷狀態之后,且第二次調用檢驗完中斷狀態前,當前線程再次中斷的情況除外)。

    文檔已經解釋得很詳細,intermpted() 方法具有清除狀態的功能,所以第二次調用 interrupted() 方法返回的值是 false。

    isInterrupted() 方法
    介紹完 interrupted() 方法后再來看一下 isInterrupted() 方法。isInterrupted() 方法的聲明如下:

    public boolean isInterrupted()

    從聲明中可以看出 isIntermpted() 方法不是 static 的。使用 isInterrupted() 方法來判斷線程是否停止,具體代碼如下:

    public class Test {public static void main(String[] args){try{MyThread thread=new MyThread();thread.start();Thread.sleep(100);thread.interrupt();System.out.println("是否停止1?="+thread.isInterrupted());System.out.println("是否停止2?="+thread.isInterrupted());}catch(InterruptedException e){System.out.println("main catch");e.printStackTrace();}System.out.println("end!");} }

    程序運行結果如下所示。

    i=498 是否停止1=true i=499 是否俜止2=true i=500 end! i=501 i=502

    從程序的運行結果中可以看到,isInterrupted() 方法并未清除狀態標識,所以打印了兩個 true。經過上面示例的驗證總結一下這兩個方法。

    • this.interrupted():測試當前線程是否已經是中斷狀態,執行后具有將狀態標識清除為 false 的功能。
    • this.islnterrupted():測試線程 Thread 對象是否已經是中斷狀態,但不清除狀態標識。

    異常法停止線程

    有了前面學習過的知識,就可在線程中用 for 語句來判斷線程是否為停止狀態,如果是停止狀態,則后面的代碼不再運行。

    例 3
    下面的線程類 MyThread 演示了在線程中使用 for 循環,并在循環中調用 intermpted() 方法判斷線程是否停止。

    public class MyThread extends Thread {@Overridepublic void run(){super.run();for(int i=0;i<500000;i++){if(this.interrupted()){ //如果當前線程處于停止狀態System.out.println("已經是停止狀態了!我要退出了!");break;}System.out.println("i="+(i+1));}} } public class Test {public static void main(String[] args){try{ MyThread thread=new MyThread(); thread.start(); //啟動線程Thread.sleep(2000); //延時2000毫秒thread.interrupt(); //停止線程}catch(InterruptedException e){ //捕捉線程停止異常System.out.println("main catch"); e.printStackTrace(); } System.out.println("end!"); //主線程結束時輸出}}

    上述代碼啟動 MyThread 線程后延時 2000 毫秒,之后將線程停止。為避免主線程崩潰使用 catch 捕捉了 InterruptedException 異常,此時會輸出“main catch”。在主線程執行結束后會輸出“end!”。程序執行的輸出結果如下所示。

    ...... i=271597 i=271598 已經是停止狀態了!我要退出了! end!

    從程序執行的結果可以看到,在示例中雖然停止了線程,但如果 for 語句下面還有語句,還是會繼續運行的。

    下面對 MyThread線程進行修改,如下所示是 run() 方法的代碼:

    public void run() { super.run(); for(int i=0;i<500000;i++){ if(this.interrupted()){ System.out.println("已經是停止狀態了!我要退出了!"); break; } System.out.println("i="+(i+1)); } System.out.println("我被輸出,如果此代碼是for又繼續運行,線程并未停止!"); }

    此時的運行效果如下所示,說明線程仍然在繼續運行。

    ...... i=233702 i=233703 end! 已經是停止狀態了!我要退出了! 我被輸出,如果此代碼是for又繼續運行,線程并未停止!

    那該如何解決線程停止后,語句仍然繼續運行的問題呢?解決的辦法是在線程中捕捉線程停止異常,如下為修改后的 run() 方法代碼。

    public void run() { super.run(); try{ for(int i=0;i<500000;i++){ if(this.interrupted()){ System.out.println("已經是停止狀態了!我要退出了!"); throw new InterruptedException(); } System.out.println("i=" + (i + 1)); } System.out.println("我在for下面"); }catch(InterruptedException e){ System.out.println("進MyThread15.java類run方法中的catch了!"); e.printStackTrace(); } }

    再次運行程序,當線程處于停止狀態后,如果 for 循環中的代碼繼續執行將會拋出 InterruptedException 異常,運行結果如下所示。

    ...... i=251711 i=251712 i=251713 已經是停止狀態了!我要退出了! end! 進MyThread15.java類run方法中的catch了! java.lang.InterruptedExceptionat text.MyThread.run(MyThread.java:16)

    在休眠中停止

    如果線程在 sleep() 狀態下停止,會是什么效果呢?

    例 4
    下面通過一個案例來演示這種情況。

    public class MyThread extends Thread {@Overridepublic void run(){super.run();try{System.out.println("run begin");Thread.sleep(200000);System.out.println("run end");}catch(Exception e){System.out.println("在休眠中被停止!進入catch!"+this.isInterrupted());e.printStackTrace();}} } public class Test {public static void main(String[] args){try{MyThread thread=new MyThread();thread.start();thread.sleep(200);thread.interrupt();}catch(Exception e){System.out.println("main catch");e.printStackTrace();}System.out.println("end!");}}

    在上述代碼中啟動 MyThread16 線程后休眠了 200 毫秒,之后調用 interrupt() 方法停止線程,運行結果如下所示。

    run begin end! 在休眠中被停止!進入catch!false java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at text.MyThread.run(MyThread.java:12)

    從運行結果來看,如果在休眠狀態下停止某一線程則會拋出進入 InterruptedException 異常,所以會進入 catch 語句塊清除停止狀態值,使之變成 false。

    例 5
    這個示例是先休眠再停止線程,下面再編寫一個案例來演示先停止再休眠線程的情況:

    public class MyThread extends Thread {@Overridepublic void run(){super.run();try{for(int i=0;i<1000;i++){System.out.println("i="+(i+1));}System.out.println("run begin");Thread.sleep(200);System.out.println("run end");}catch(InterruptedException e){System.out.println("先停止,再遇到了sleep!進入catch!");e.printStackTrace();}} } public class Test {public static void main(String[] args){MyThread17 thread=new MyThread17();thread.start();thread.interrupt();System.out.println("end!");} }

    在上述代碼中啟動 MyThread 線程后沒有進行延時,馬上調用 interrupt() 方法進行停止線程,但是在 MyThread線程中有一個 200 毫秒的延時。運行程序后,首先會看到下所示的輸出,說明主線程執行完畢。

    end! i=1 i=2 i=3 i=4 i=5 i=6 ......

    稍等片刻后,將會看到如下所示的異常,說明線程停止了。

    ...... i=999 i=1000 run begin 先停止,再遇到了sleep!進入catch! java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at text.MyThread.run(MyThread.java:16)

    強制停止線程

    調用 stop() 方法可以在任意情況下強制停止一個線程。下面通過一個案例來演示 stop() 停止線程的方法。

    public class MyThread extends Thread {private int i=0;@Overridepublic void run(){try{while (true){i++;System.out.println("i=" + i);Thread.sleep(1000);}}catch(InterruptedException e){//TODO Auto-generated catch blocke.printStackTrace();}} }

    如上述代碼所示,MyThread線程中包含一個死循環,該循環每隔 1000 毫秒執行一次,每次將 i 的值遞增 1 并輸出。

    調用 MyThread線程的主線程代碼如下:

    public class Test {@SuppressWarnings("deprecation")public static void main(String[] args){try{MyThread thread=new MyThread();thread.start();Thread.sleep(8000);thread.stop();}catch(InterruptedException e){// TODO Auto-generated catch blocke.printStackTrace();}} }

    如上述代碼所示,MyThread 線程在啟動后有一個 8000 毫秒的延時,在這段時間內會循環 9 次,之后 stop() 方法被執行從而線程停止。運行后的輸出如下所示。

    i=1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9

    注意:調用 stop() 方法時會拋出 java.lang.ThreadDeath 異常,但在通常情況下,此異常不需要顯式地捕捉。

    釋放鎖的不良后果

    從 JDK 1.6 以后 stop() 方法已經被作廢,因為如果強制讓線程停止則有可能使一些清理性的工作得不到完成。另外一個情況就是對鎖定的對象進行了“解鎖”,導致數據得不到同步的處理,出現數據不一致的問題。

    使用 stop() 釋放鎖將會給數據造成不一致性的結果。如果出現這樣的情況,程序處理的數據就有可能遭到破壞,最終導致程序執行的流程錯誤,一定要特別注意。

    例 6
    下面通過一個案例來演示這種情況。案例使用了一個名為 SynchronizedObject 的實體類,該類代碼如下:

    public class SynchronizedObject {private String username="root";private String password="root";public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}synchronized public void printString(String username,String password){try{this.username=username;Thread.sleep(100000);this.password=password;}catch(Exception e){e.printStackTrace();}} }

    如上述代碼所示,SynchronizedObject 類包含用戶名和密碼兩個成員,printString() 方法用于對這兩個成員進行賦值,但是在設置密碼之前有一個休眠時間。

    下面編寫一個線程來對 SynchronizedObject 類進行實例化,并調用 printString() 方法。線程代碼如下:

    public class MyThread extends Thread {private SynchronizedObject object;public MyThread(SynchronizedObject object){super();this.object=object;}@Overridepublic void run(){object.printString("admin", "1234");} } public class Test {public static void main(String[] args){try{SynchronizedObject object=new SynchronizedObject();MyThread thread=new MyThread(object);thread.start();thread.sleep(500);thread.stop();System.out.println("用戶名:"+object.getUsername());System.out.println("密碼:"+object.getPassword());}catch(Exception e){e.printStackTrace();}}}

    在上述代碼中創建一個 SynchronizedObject 類實例,并將該實例作為參數傳遞給 MyThread線程。MyThread 線程啟動后將立即調用 object.printString('fadminn,"123456") 方法,而在 printString() 方法內有一個較長時間的休眠。該休眠時間大于主線程的休眠時間,所以主線程會繼續往下執行,當執行到 stop() 方法時線程被強制停止。

    程序最后的運行結果如下所示。

    用戶名:admin 密碼:root

    由于 stop() 方法已經在中被標明是“作廢/過期”的方法,顯然它在功能上具有缺陷,所以不建議在程序中使用 stop() 方法。

    使用 return 停止線程

    除了上面介紹的方法外,還可以將 intermpt() 方法與 return 結合使用來實現停止線程的效果。

    例 7
    下面通過一個案例來演示這種情況。如下所示為案例中使用 MyThread 線程類的代碼。

    public class MyThread extends Thread {@Overridepublic void run(){while (true){if (this.isInterrupted()){System.out.println("停止了!");return;}System.out.println("timer="+System.currentTimeMillis());}} }

    調用 MyThread 線程的主線程代碼如下:

    public class Test {public static void main(String[] args) throws InterruptedException{MyThread t=new MyThread();t.start();Thread.sleep(2000);t.interrupt();} }

    程序執行后的結果如下所示。

    ...... timer=1540977194784 timer=1540977194784 timer=1540977194784 timer=1540977194784 timer=1540977194784 停止了!

    從程序的執行結果中可以看到成功停止了線程,不過還是建議使用“拋異常”的方法來實現線程的停止,因為在 catch 塊中還可以將異常向上拋,使線程停止的事件得以傳播。

    總結

    以上是生活随笔為你收集整理的停止(终止)线程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。