Java并發(fā)編程示例(四):可控的線程中斷
在上一節(jié)“線程中斷”中,我們講解了如何中斷一個(gè)正在執(zhí)行的線程以及為了中斷線程,我們必須對Thread動(dòng)點(diǎn)什么手腳。一般情況下,我們可以使用上一節(jié)介紹的中斷機(jī)制。但是,如果線程實(shí)現(xiàn)了一個(gè)分配到多個(gè)方法中的復(fù)雜算法,或者方法調(diào)用中有一個(gè)遞歸調(diào)用,我們應(yīng)該使用更好的方式來控制線程的中斷。為此,Java提供了InterruptedException異常。當(dāng)檢測到中斷請求時(shí),可以拋出此異常,并且在run()方法中捕獲。
在本節(jié),我們將使用一個(gè)線程查找指定目錄及其子目錄下文件來演示通過使用InterruptedException異??刂凭€程中斷。
知其然
按照下面所示步驟,實(shí)現(xiàn)示例程序。
1.創(chuàng)建一個(gè)名為FileSearch的類,并且實(shí)現(xiàn)Runnable接口。代碼如下:
public class FileSearch implements Runnable {
2.聲明兩個(gè)變量,一個(gè)用于需要查找的文件名,一個(gè)用于初始化查找的目錄;實(shí)現(xiàn)類的構(gòu)造函數(shù),并用構(gòu)造函數(shù)的參數(shù)初始化剛剛聲明的兩個(gè)變量。代碼如下:
private String initPath;
private String fileName;
public FileSearch(String initPath, String fileName) {
this.initPath = initPath;
this.fileName = fileName;
}
3.實(shí)現(xiàn)run()方法,該方法檢查fileName是否一個(gè)路徑名稱。如果是,則調(diào)用directoryProcess()方法進(jìn)行處理。directoryProcess()方法會拋出InterruptedException異常,所以我們需要捕獲該異常。代碼如下:
@Override
public void run() {
File file = new File(initPath);
if (file.isDirectory()) {
try {
directoryProcess(file);
} catch (InterruptedException e) {
System.out.printf("%s: The search has been interrupted",
Thread.currentThread().getName());
}
}
}
原文中,提到的方法名稱為processDirectory()。但是,根據(jù)下文的程序,屬于筆誤。故改正。
4.實(shí)現(xiàn)directoryProcess()方法。該方法讀取指定目錄下的所有文件以及子目錄再進(jìn)行處理。對于每一個(gè)目錄,該方法進(jìn)行一個(gè)遞歸調(diào)用,來處理參數(shù)指定的目錄。對于每一個(gè)文件,該方法會調(diào)用fileProcess()方法。在處理完所有的目錄以及文件后,該方法會檢查線程是否被中斷,這是拋出一個(gè)InterruptedException異常。代碼如下:
/**
* 處理一個(gè)目錄
*
* @param file 需要處理的目錄
* @throws InterruptedException
*/
private void directoryProcess(File file) throws InterruptedException {
File[] list = file.listFiles();
if (null != list) {
for (int i = 0; i < list.length; i++) {
if (list[i].isDirectory()) {
directoryProcess(list[i]);
} else {
fileProcess(list[i]);
}
}
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
5.實(shí)現(xiàn)fileProcess()方法,該方法會比較正在處理的文件和需要查找的文件名。如果文件名稱相等,則在控制臺打印出一條信息。然后,線程檢查是否被中斷,如果是,則拋出InterruptedException異常。代碼如下:
/**
* 處理的文件
*
* @param file 需要處理的文件
* @throws InterruptedException
*/
private void fileProcess(File file) throws InterruptedException {
if (file.getName().equals(fileName)) {
System.out.printf("%s : %s\n",
Thread.currentThread().getName(),
file.getAbsolutePath());
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
6.現(xiàn)在,來實(shí)現(xiàn)示例的主類,并且實(shí)現(xiàn)main()方法。代碼如下:
public class Main {
public static void main(String[] args) {
7.創(chuàng)建并初始化FileSearch對象,然后創(chuàng)建一個(gè)Thread對象,來執(zhí)行該任務(wù)。然后,啟動(dòng)該線程。代碼如下:
FileSearch fileSearch = new FileSearch("C:\\", "autoexec.bat");
Thread thread = new Thread(fileSearch);
thread.start();
8.等待十秒鐘,然后中斷線程。代碼如下:
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
9.執(zhí)行該示例,查看結(jié)果。
知其所以然
下面是線程執(zhí)行的結(jié)果。從輸出中可以看出,當(dāng)FileSearch檢測到被中斷后,如何中止線程執(zhí)行的。
Thread-0 : C:\autoexec.bat
Thread-0: The search has been interrupted
本示例中,我們使用Java的異常來控制線程的中斷。當(dāng)你運(yùn)行示例時(shí),程序會檢測指定目錄及其子目錄是否包含目標(biāo)文件。例如,如果輸入\b\c\d,程序?qū)f歸調(diào)用三次directoryProcess()方法。當(dāng)線程檢測到其被中斷,則會拋出InterruptedException異常,無論執(zhí)行多少次遞歸調(diào)用,程序都會開始執(zhí)行run()方法。
永無止境
InterruptedException異常一般由Java并發(fā)API,例如sleep()方法,拋出。
拿來主義
本文是從 《Java 7 Concurrency Cookbook》 (D瓜哥竊譯為 《Java7并發(fā)示例集》 )翻譯而來,僅作為學(xué)習(xí)資料使用。沒有授權(quán),不得用于任何商業(yè)行為。
小有所成
FileSearch類的完整代碼
package com.diguage.books.concurrencycookbook.chapter1.recipe4;
import java.io.File;
/**
* Date: 2013-09-18
* Time: 18:21
*/
public class FileSearch implements Runnable {
private String initPath;
private String fileName;
/**
* 初始化構(gòu)造函數(shù)
*
* @param initPath 需要進(jìn)行查找的目錄
* @param fileName 需要查找的文件名稱
*/
public FileSearch(String initPath, String fileName) {
this.initPath = initPath;
this.fileName = fileName;
}
@Override
public void run() {
File file = new File(initPath);
if (file.isDirectory()) {
try {
directoryProcess(file);
} catch (InterruptedException e) {
System.out.printf("%s: The search has been interrupted",
Thread.currentThread().getName());
}
}
}
/**
* 處理一個(gè)目錄
*
* @param file 需要處理的目錄
* @throws InterruptedException
*/
private void directoryProcess(File file) throws InterruptedException {
File[] list = file.listFiles();
if (null != list) {
for (int i = 0; i < list.length; i++) {
if (list[i].isDirectory()) {
directoryProcess(list[i]);
} else {
fileProcess(list[i]);
}
}
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
/**
* 處理的文件
*
* @param file 需要處理的文件
* @throws InterruptedException
*/
private void fileProcess(File file) throws InterruptedException {
if (file.getName().equals(fileName)) {
System.out.printf("%s : %s\n",
Thread.currentThread().getName(),
file.getAbsolutePath());
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
}
Main類的完整代碼
package com.diguage.books.concurrencycookbook.chapter1.recipe4;
import java.util.concurrent.TimeUnit;
/**
* Date: 2013-09-18
* Time: 19:28
*/
public class Main {
public static void main(String[] args) {
FileSearch fileSearch = new FileSearch("C:\\", "autoexec.bat");
Thread thread = new Thread(fileSearch);
thread.start();
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
相關(guān)文章
springboot集成mqtt的實(shí)踐開發(fā)
本篇文章主要介紹了springboot集成mqtt的實(shí)踐開發(fā),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08如何實(shí)現(xiàn)nohup?java進(jìn)程號一直在變方法步驟詳解
這篇文章主要為大家介紹了如何實(shí)現(xiàn)nohup?java進(jìn)程號一直在變方法步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Java 凍結(jié)或解除凍結(jié)Excel中的行和列的方法
這篇文章主要介紹了Java 凍結(jié)或解除凍結(jié)Excel中的行和列的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03springboot項(xiàng)目中application.properties無法變成小樹葉問題解決方案
這篇文章主要介紹了springboot項(xiàng)目中application.properties無法變成小樹葉問題解決,本文通過圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09SpringBoot中@ComponentScan的使用詳解
這篇文章主要介紹了SpringBoot中@ComponentScan的使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11利用Java簡單實(shí)現(xiàn)一個(gè)代碼行數(shù)統(tǒng)計(jì)器方法實(shí)例
這篇文章主要給大家介紹了關(guān)于如何利用Java簡單實(shí)現(xiàn)一個(gè)代碼行數(shù)統(tǒng)計(jì)器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11