欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

正確結(jié)束Java線程的方法

 更新時間:2019年05月31日 15:07:43   作者:展翅而飛  
線程的啟動很簡單,但用戶可能隨時取消任務(wù),怎么樣讓跑起來的線程正確地結(jié)束,這是今天要討論的話題。下面小編來和大家一起學(xué)習(xí)一下吧

使用標志位

很簡單地設(shè)置一個標志位,名稱就叫做isCancelled。啟動線程后,定期檢查這個標志位。如果isCancelled=true,那么線程就馬上結(jié)束。

public class MyThread implements Runnable{
private volatile boolean isCancelled;
public void run(){
while(!isCancelled){
//do something
}
}
public void cancel(){ isCancelled=true; }
}

注意的是,isCancelled需要為volatile,保證線程讀取時isCancelled是最新數(shù)據(jù)。
我以前經(jīng)常用這種簡單方法,在大多時候也很有效,但并不完善。考慮下,如果線程執(zhí)行的方法被阻塞,那么如何執(zhí)行isCancelled的檢查呢?線程有可能永遠不會去檢查標志位,也就卡住了。

使用中斷

Java提供了中斷機制,Thread類下有三個重要方法。

  • public void interrupt()
  • public boolean isInterrupted()
  • public static boolean interrupted(); // 清除中斷標志,并返回原狀態(tài)

每個線程都有個boolean類型的中斷狀態(tài)。當(dāng)使用Thread的interrupt()方法時,線程的中斷狀態(tài)會被設(shè)置為true。
下面的例子啟動了一個線程,循環(huán)執(zhí)行打印一些信息。使用isInterrupted()方法判斷線程是否被中斷,如果是就結(jié)束線程。

public class InterruptedExample {
public static void main(String[] args) throws Exception {
InterruptedExample interruptedExample = new InterruptedExample();
interruptedExample.start();
}
public void start() {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(3000);
myThread.cancel();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class MyThread extends Thread{
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("test");
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("interrupt");
//拋出InterruptedException后中斷標志被清除,標準做法是再次調(diào)用interrupt恢復(fù)中斷
Thread.currentThread().interrupt();
}
}
System.out.println("stop");
}
public void cancel(){
interrupt();
}
}
}

對線程調(diào)用interrupt()方法,不會真正中斷正在運行的線程,只是發(fā)出一個請求,由線程在合適時候結(jié)束自己。

例如Thread.sleep這個阻塞方法,接收到中斷請求,會拋出InterruptedException,讓上層代碼處理。這個時候,你可以什么都不做,但等于吞掉了中斷。因為拋出InterruptedException后,中斷標記會被重新設(shè)置為false!看sleep()的注釋,也強調(diào)了這點。

@throws InterruptedException
if any thread has interrupted the current thread. 
The interrupted status of the current thread is 
cleared when this exception is thrown.
public static native void sleep(long millis) throws InterruptedException;

記得這個規(guī)則:什么時候都不應(yīng)該吞掉中斷!每個線程都應(yīng)該有合適的方法響應(yīng)中斷!

所以在InterruptedExample例子里,在接收到中斷請求時,標準做法是執(zhí)行Thread.currentThread().interrupt()恢復(fù)中斷,讓線程退出。

從另一方面談起,你不能吞掉中斷,也不能中斷你不熟悉的線程。如果線程沒有響應(yīng)中斷的方法,你無論調(diào)用多少次interrupt()方法,也像泥牛入海。

用Java庫的方法比自己寫的要好

自己手動調(diào)用interrupt()方法來中斷程序,OK。但是Java庫提供了一些類來實現(xiàn)中斷,更好更強大。

Executor框架提供了Java線程池的能力,ExecutorService擴展了Executor,提供了管理線程生命周期的關(guān)鍵能力。其中,ExecutorService.submit返回了Future對象來描述一個線程任務(wù),它有一個cancel()方法。

下面的例子擴展了上面的InterruptedExample,要求線程在限定時間內(nèi)得到結(jié)果,否則觸發(fā)超時停止。

public class InterruptByFuture {
public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newSingleThreadExecutor();
Future<?> task = es.submit(new MyThread());
try {
//限定時間獲取結(jié)果
task.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
//超時觸發(fā)線程中止
System.out.println("thread over time");
} catch (ExecutionException e) {
throw e;
} finally {
boolean mayInterruptIfRunning = true;
task.cancel(mayInterruptIfRunning);
}
}
private static class MyThread extends Thread {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) { 
try {
System.out.println("count");
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("interrupt");
Thread.currentThread().interrupt();
}
}
System.out.println("thread stop");
}
public void cancel() {
interrupt();
}
}
}

Future的get方法可以傳入時間,如果限定時間內(nèi)沒有得到結(jié)果,將會拋出TimeoutException。此時,可以調(diào)用Future的cancel()方法,對任務(wù)所在線程發(fā)出中斷請求。
cancel()有個參數(shù)mayInterruptIfRunning,表示任務(wù)是否能夠接收到中斷。

  • mayInterruptIfRunning=true時,任務(wù)如果在某個線程中運行,那么這個線程能夠被中斷;
  • mayInterruptIfRunning=false時,任務(wù)如果還未啟動,就不要運行它,應(yīng)用于不處理中斷的任務(wù)

要注意,mayInterruptIfRunning=true表示線程能接收中斷,但線程是否實現(xiàn)了中斷不得而知。線程要正確響應(yīng)中斷,才能真正被cancel。

線程池的shutdownNow()會嘗試停止池內(nèi)所有在執(zhí)行的線程,原理也是發(fā)出中斷請求。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Spring 注解之@Import 注入的各種花活

    詳解Spring 注解之@Import 注入的各種花活

    這篇文章主要介紹了詳解Spring 注解之@Import 注入的各種花活,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • 總結(jié)十個實用但偏執(zhí)的Java編程技術(shù)

    總結(jié)十個實用但偏執(zhí)的Java編程技術(shù)

    Java是世界上最流行的程序語言,從1995年問世以來,Java的生態(tài)系統(tǒng)在一直在蓬勃的發(fā)展著。下面這篇文章主要總結(jié)了十個實用但偏執(zhí)的Java編程技術(shù),需要的朋友可以參考借鑒,下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-01-01
  • Java基于分治法實現(xiàn)的快速排序算法示例

    Java基于分治法實現(xiàn)的快速排序算法示例

    這篇文章主要介紹了Java基于分治法實現(xiàn)的快速排序算法,結(jié)合實例形式分析了java基于分治法的快速排序相關(guān)實現(xiàn)技巧,代碼中備有較為詳細的注釋說明便于理解,需要的朋友可以參考下
    2017-12-12
  • 簡單分析java中CMS回收器

    簡單分析java中CMS回收器

    在本篇文章里我們給大家分享了關(guān)于java中CMS回收器的相關(guān)知識點內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)下。
    2018-10-10
  • Maven中resources標簽的用法詳解

    Maven中resources標簽的用法詳解

    本文主要介紹了Maven中resources標簽的用法詳解,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java連接Redis全過程講解

    Java連接Redis全過程講解

    這篇文章主要介紹了Java連接Redis全過程講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Springboot?格式化LocalDateTime的方法

    Springboot?格式化LocalDateTime的方法

    這篇文章主要介紹了Springboot格式化LocalDateTime的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • Java多線程編程安全退出線程方法介紹

    Java多線程編程安全退出線程方法介紹

    這篇文章主要介紹了Java多線程編程安全退出線程方法介紹,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10
  • Java如何通過File類方法刪除指定文件夾中的全部文件

    Java如何通過File類方法刪除指定文件夾中的全部文件

    這篇文章主要給大家介紹了關(guān)于Java如何通過File類方法刪除指定文件夾中的全部文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解

    Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解

    這篇文章主要介紹了 Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評論