1. 程式人生 > >多執行緒的使用——中斷執行緒詳解(Interrupt)

多執行緒的使用——中斷執行緒詳解(Interrupt)

    在JAVA中,曾經使用stop方法來停止執行緒,然而,該方法具有固有的不安全性,因而已經被拋棄(Deprecated)。那麼應該怎麼結束一個程序呢?官方文件中對此有詳細說明:《為何不贊成使用 Thread.stop、Thread.suspend 和 Thread.resume?》。在此引用stop方法的說明:

1. Why is Thread.stop deprecated? Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future. 大概意思是: 因為該方法本質上是不安全的。停止一個執行緒將釋放它已經鎖定的所有監視器(作為沿堆疊向上傳播的未檢查 ThreadDeath 異常的一個自然後果)。如果以前受這些監視器保護的任何物件都處於一種不一致的狀態,則損壞的物件將對其他執行緒可見,這有可能導致任意的行為。此行為可能是微妙的,難以察覺,也可能是顯著的。不像其他的未檢查異常,ThreadDeath異常會在後臺殺死執行緒,因此,使用者並不會得到警告,提示他的程式可能已損壞。這種損壞有可能在實際破壞發生之後的任何時間表現出來,也有可能在多小時甚至在未來的很多天後。 在文件中還提到,程式設計師不能通過捕獲ThreadDeath異常來修復已破壞的物件。具體原因見原文。 既然stop方法不建議使用,那麼應該用什麼方法來代理stop已實現相應的功能呢? 1、通過修改共享變數來通知目標執行緒停止執行
大部分需要使用stop的地方應該使用這種方法來達到中斷執行緒的目的。 這種方法有幾個要求或注意事項: (1)目標執行緒必須有規律的檢查變數,當該變數指示它應該停止執行時,該執行緒應該按一定的順序從它執行的方法中返回。 (2)該變數必須定義為volatile,或者所有對它的訪問必須同步(synchronized)。 例如: 假如你的applet包括start,stop,run幾個方法:
  1. private Thread blinker; 
  2. publicvoid start() { 
  3.     blinker = new Thread(this); 
  4.     blinker.start(); 
  5. publicvoid stop() { 
  6.     blinker.stop();  // UNSAFE!
  7. publicvoid run() { 
  8.     Thread thisThread = Thread.currentThread(); 
  9.     while (true) { 
  10.         try { 
  11.         thisThread.sleep(interval); 
  12.         } catch (InterruptedException e){ 
  13.         } 
  14.         repaint(); 
  15.     } 
你可以使用如下方式避免使用Thread.stop方法:
  1. private
    volatile Thread blinker; 
  2. publicvoid stop() { 
  3.     blinker = null
  4. publicvoid run() { 
  5.     Thread thisThread = Thread.currentThread(); 
  6.     while (blinker == thisThread) { 
  7.         try { 
  8.             thisThread.sleep(interval); 
  9.         } catch (InterruptedException e){ 
  10.         } 
  11.         repaint(); 
  12.     } 
2、通過Thread.interrupt方法中斷執行緒 通常情況下,我們應該使用第一種方式來代替Thread.stop方法。然而以下幾種方式應該使用Thread.interrupt方法來中斷執行緒(該方法通常也會結合第一種方法使用)。 一開始使用interrupt方法時,會有莫名奇妙的感覺:難道該方法有問題? API文件上說,該方法用於"Interrupts this thread"。請看下面的例子:
  1. package com.polaris.thread; 
  2. publicclass TestThread implements Runnable{ 
  3.     boolean stop = false
  4.     publicstaticvoid main(String[] args) throws Exception { 
  5.         Thread thread = new Thread(new TestThread(),"My Thread"); 
  6.         System.out.println( "Starting thread..." ); 
  7.         thread.start(); 
  8.         Thread.sleep( 3000 ); 
  9.         System.out.println( "Interrupting thread..." ); 
  10.         thread.interrupt(); 
  11.         System.out.println("執行緒是否中斷:" + thread.isInterrupted()); 
  12.         Thread.sleep( 3000 ); 
  13.         System.out.println("Stopping application..." ); 
  14.     } 
  15.     publicvoid run() { 
  16.         while(!stop){ 
  17.             System.out.println( "My Thread is running..." ); 
  18.             // 讓該迴圈持續一段時間,使上面的話列印次數少點
  19.             long time = System.currentTimeMillis(); 
  20.             while((System.currentTimeMillis()-time < 1000)) { 
  21.             } 
  22.         } 
  23.         System.out.println("My Thread exiting under request..." ); 
  24.     } 
執行後的結果是: Starting thread... My Thread is running... My Thread is running... My Thread is running... My Thread is running... Interrupting thread... 執行緒是否中斷:true My Thread is running... My Thread is running... My Thread is running... Stopping application... My Thread is running... My Thread is running... …… 應用程式並不會退出,啟動的執行緒沒有因為呼叫interrupt而終止,可是從呼叫isInterrupted方法返回的結果可以清楚地知道該執行緒已經中斷了。那位什麼會出現這種情況呢?到底是interrupt方法出問題了還是isInterrupted方法出問題了?在Thread類中還有一個測試中斷狀態的方法(靜態的)interrupted,換用這個方法測試,得到的結果是一樣的。由此似乎應該是interrupt方法出問題了。於是,在網上有一篇文章:《 Java Thread.interrupt 害人! 中斷JAVA執行緒》,它詳細的說明了應該如何使用interrupt來中斷一個執行緒的執行。 實際上,在JAVA API文件中對該方法進行了詳細的說明。該方法實際上只是設定了一箇中斷狀態,當該執行緒由於下列原因而受阻時,這個中斷狀態就起作用了: (1)如果執行緒在呼叫 Object 類的 wait()、wait(long) 或 wait(long, int) 方法,或者該類的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法過程中受阻,則其中斷狀態將被清除,它還將收到一個InterruptedException異常。這個時候,我們可以通過捕獲InterruptedException異常來終止執行緒的執行,具體可以通過return等退出或改變共享變數的值使其退出。 (2)如果該執行緒在可中斷的通道上的 I/O 操作中受阻,則該通道將被關閉,該執行緒的中斷狀態將被設定並且該執行緒將收到一個 ClosedByInterruptException。這時候處理方法一樣,只是捕獲的異常不一樣而已。 其實對於這些情況有一個通用的處理方法:
  1. package com.polaris.thread; 
  2. publicclass TestThread2 implements Runnable{ 
  3.     boolean stop = false
  4.     publicstaticvoid main(String[] args) throws Exception { 
  5.         Thread thread = new Thread(new TestThread2(),"My Thread2"); 
  6.         System.out.println( "Starting thread..." ); 
  7.         thread.start(); 
  8.         Thread.sleep( 3000 ); 
  9.         System.out.println( "Interrupting thread..." ); 
  10.         thread.interrupt(); 
  11.         System.out.println("執行緒是否中斷:" + thread.isInterrupted()); 
  12.         Thread.sleep( 3000 ); 
  13.         System.out.println("Stopping application..." ); 
  14.     } 
  15.     publicvoid run() { 
  16.         while(!stop){ 
  17.             System.out.println( "My Thread is running..." ); 
  18.             // 讓該迴圈持續一段時間,使上面的話列印次數少點
  19.             long time = System.currentTimeMillis(); 
  20.             while((System.currentTimeMillis()-time < 1000)) { 
  21.             } 
  22.             if(Thread.currentThread().isInterrupted()) { 
  23.                 return
  24.             } 
  25.         } 
  26.         System.out.println("My Thread exiting under request..." ); 
  27.     } 
因為呼叫interrupt方法後,會設定執行緒的中斷狀態,所以,通過監視該狀態來達到終止執行緒的目的。 總結:程式應該對執行緒中斷作出恰當的響應。響應方式通常有三種:(來自溫紹錦(暱稱:溫少):http//www.cnblogs.com/jobs/)

注意:interrupted與isInterrupted方法的區別(見API文件)

引用一篇文章

當外部執行緒對某執行緒呼叫了thread.interrupt()方法後,java語言的處理機制如下:

如果該執行緒處在可中斷狀態下,(呼叫了xx.wait(),或者Selector.select(),Thread.sleep()等特定會發生阻塞的api),那麼該執行緒會立即被喚醒,同時會受到一個InterruptedException,同時,如果是阻塞在io上,對應的資源會被關閉。如果該執行緒接下來不執行“Thread.interrupted()方法(不是interrupt),那麼該執行緒處理任何io資源的時候,都會導致這些資源關閉。當然,解決的辦法就是呼叫一下interrupted(),不過這裡需要程式設計師自行根據程式碼的邏輯來設定,根據自己的需求確認是否可以直接忽略該中斷,還是應該馬上退出。

如果該執行緒處在不可中斷狀態下,就是沒有呼叫上述api,那麼java只是設定一下該執行緒的interrupt狀態,其他事情都不會發生,如果該執行緒之後會呼叫行數阻塞API,那到時候執行緒會馬會上跳出,並丟擲InterruptedException,接下來的事情就跟第一種狀況一致了。如果不會呼叫阻塞API,那麼這個執行緒就會一直執行下去。除非你就是要實現這樣的執行緒,一般高效能的程式碼中肯定會有wait(),yield()之類出讓cpu的函式,不會發生後者的情況。

相關推薦

執行的使用——中斷執行(Interrupt)

    在JAVA中,曾經使用stop方法來停止執行緒,然而,該方法具有固有的不安全性,因而已經被拋棄(Deprecated)。那麼應該怎麼結束一個程序呢?官方文件中對此有詳細說明:《為何不贊成使用 Thread.stop、Thread.suspend 和 Threa

執行之Future使用

什麼是Future Future是一個未來物件,裡面儲存這執行緒處理結果,它像一個提貨憑證,拿著它你可以隨時去提取結果 什麼時候使用 在兩種情況下,離開Future幾乎很難辦。 一種情況是拆分訂單,比如你的應用收到一個批量訂單,此時如果要求最快的處理訂單,那麼需要併發

Android 執行之HandlerThread 完全

  之前對執行緒也寫過幾篇文章,不過倒是沒有針對android,因為java與android線上程方面大部分還是相同,不過本篇我們要介紹的是android的專屬類HandlerThread,因為HandlerThread在設定思想上還是挺值得我們學習的,那麼我們下面來

Java執行Condition介面原理

Condition介面提供了類似Object的監視器方法,與Lock配合可以實現等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的 Condition介面詳解 Condition定義了等待/通知兩種型別的方法,當前執行緒呼叫這些方法時,需要提前獲

執行之重排序

重排序 重排序是指編譯器和處理器為了優化程式效能而對指令序列進行重新排序的一種手段。 資料依賴性 如果兩個操作訪問同一個變數,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在資料的依賴性。資料依賴分為3中型別,如下表所示: 上面3中情況,只要重排序兩個操作的順序。程式的結

C#基礎系列:執行的常見用法

前言:此篇就主要從博主使用過的幾種多執行緒的用法從應用層面大概介紹下。文中觀點都是博主個人的理解,如果有不對的地方望大家指正~~ 1、多執行緒:使用多個處理控制代碼同時對多個任務進行控制處理的一種技術。據博主的理解,多執行緒就是該應用的主執行緒任命其他多個執行緒去協

Android 執行程式設計之 HandlerThread

    HandlerThread有那些特點: HandlerThread本質上是一個執行緒類,它繼承了Thread; HandlerThread有自己的內部Looper物件,可以進行looper迴圈; 通過獲取HandlerThread的looper物件傳

Java執行同步和非同步

1. 多執行緒併發時,多個執行緒同時請求同一資源,必然導致此資源的資料不安全。 2. 執行緒池 在WEB服務中,對於web伺服器的響應速度必須儘可能的快,這就容不得在使用者提交請求按鈕後,再建立執行緒提供服務。為了減少使用者的等待時間,執行緒必須預先建立,放線上程池中,執行

入坑JAVA執行併發(八)ThreadLocal使用和原理

  ThreadLocal是一個用於儲存多執行緒變數的類,它可以把執行緒與設定的值對應起來,因為它為變數在每個執行緒都建立了一個副本。訪問的時候每個執行緒只能訪問到自己的副本變數。 例項 看如下程式碼: public class Main {

C#基礎系列——執行的常見用法

前言:前面幾節分別介紹了下C#基礎技術中的反射、特性、泛型、序列化、擴充套件方法、Linq to Xml等,這篇跟著來介紹下C#的另一基礎技術的使用。最近專案有點緊張,所以準備也不是特別充分。此篇就主要從博主使用過的幾種多執行緒的用法從應用層面大概介紹下。文中觀點都是博主個人的理解,如果有不對的地方望大家指正

JAVA執行Thread VS Runnable

要求 必備知識 本文要求基本瞭解JAVA程式設計知識。 開發環境 windows 7/EditPlus 演示地址 原始檔 程序與執行緒 程序是程式在處理機中的一次執行。一個程序既包括其所要執行的指令,也包括了執行指令所需的系統資源,不同程序所

執行之 Final變數

原文: http://www.tuicool.com/articles/2Yjmqy 併發程式設計網:http://ifeve.com/java-memory-model/ 總結: Final 變數在併發當中,原理是通過禁止cpu的指令集重排序(重排序詳解http://ifeve.com/java

Java 執行之synchronized關鍵字

package com.example; /** * Created by 晁東洋 on 2017/5/27. */ public class MyThreadClass { public static void main(String args[]){ Exampletest

執行執行互斥之synchronized

定義: 執行緒互斥是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。 我們都知道保證執行緒完整執行。則需要對其加鎖。使用synchronized關鍵字。在這裡鎖的物件理論上可以為任何物件。

java執行與併發程式設計

一、多執行緒1、作業系統有兩個容易混淆的概念,程序和執行緒。程序:一個計算機程式的執行例項,包含了需要執行的指令;有自己的獨立地址空間,包含程式內容和資料;不同程序的地址空間是互相隔離的;程序擁有各種資源和狀態資訊,包括開啟的檔案、子程序和訊號處理。執行緒:表示程式的執行流程

Python程序與執行程式設計及GIL

介紹如何使用python的multiprocess和threading模組進行多執行緒和多程序程式設計。 Python的多程序程式設計與multiprocess模組 python的多程序程式設計主要依靠multiprocess模組。我們先對比兩段程式碼,看看多程序程式設計的優勢。我們模擬了一個非常耗時的任

Python程序、執行、協程執行效能、效率(tqdm)

多程序實踐——multiprocessing 筆者最近在實踐多程序發現multiprocessing,真心很好用,不僅加速了運算,同時可以GPU呼叫,而且互相之間無關聯,這樣可以很放心的進行計算。 譬如(參考:多程序): from multiprocessing import Pool

Java執行池Executor框架

Java的執行緒既是工作單元,也是執行機制。從JDK 5開始,把工作單元與執行機制分離開來。工作單元包括Runnable和Callable,而執行機制由Executor框架提供。 Executor框架簡介在HotSpot VM的執行緒模型中,Java執行緒(java.lang.Thread)被一對一對映為本

美團面試題:Java-執行池 ThreadPool 專題

去美團面試,問到了什麼是執行緒池,如何使用,為什麼要用,以下做個總結。關於執行緒之前也寫過一篇文章《高階面試題總結—執行緒池還能這麼玩?》 1、什麼是執行緒池:  java.util.concurrent.Executors提供了一個 java.util.conc

java執行(上)——執行狀態及屬性

在作業系統中,我們通過分時的方法在CPU上不斷地切換處理多個程序任務,給人並行處理的感覺,這種方法在作業系統中叫做多工。多工在較低層次上擴展出多執行緒的概念,也就是指一個程式同時執行多個執行緒。這種可以同時執行一個以上的執行緒的程式,我們叫做多執行緒程式。