在上节中,我们学到如何中断线程的执行,以及如何在线程对象中控制中断。上节中用来展示线程可否被中断的范例原理比较简单。如果线程运行一个分成很多方法的复杂算法或者包含递归调用的方法,就需要更好的机制来控制线程中断。针对于此,Java提供IterruptedException异常,当探测到线程中断时抛出这个异常,并在run()方法中捕获它。
在本节中,实现一个任务,查找指定目录以及其所有子目录下确定名称的文件。用来展示如何使用IterruptedException异常来控制线程中断。
准备工作
本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。
实现过程
通过如下步骤完成范例:
-
创建FileSearch类,指定其实现Runnable接口:
public class FileSearch implements Runnable {
-
定义两个私有属性:分别是将要寻找的文件名称和初始目录路径。实现此类的构造函数,初始化两个属性:
private String initPath; private String fileName; public FileSearch(String initPath, String fileName){ this.initPath = initPath; this.fileName = fileName; }
-
实现FileSearch类的run()方法。判断fileName属性是否为目录,如果是,调用directoryProcess()方法,这个方法能够抛出IterruptedException异常,所以能够捕获到:
@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()); } } }
-
实现directoryProcess()方法。此方法将获得指定目录下的文件和子目录并进行处理。对每个目录,方法进行递归调用,遍历目录为参数。对每个文件,将调用fileProcess()方法。处理完所有文件和目录后,此方法判断线程是否已被中断,如果是的情况,会抛出一个IterruptedException异常:
private void directoryProcess(File file) throws InterruptedException{ File list[] = file.listFiles(); if(list != null) { 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(); } }
-
实现fileProcess()方法。此方法将比较正在处理的文件和需要寻找的文件,如果名称相同,控制台会输出一条信息。比较过后,线程将判断它是否已被中断,如果是的情况,会抛出一个IterruptedException异常:
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()方法的Main类:
public class Main { public static void main(String[] args) {
-
创建和初始化FileSearch类的对象和执行任务的线程,然后开始运行线程。这里使用的是Windows操作系统路径。如果用其他操作系统例如Linux或者iOS开发,更改相应路径:
FileSearch searcher = new FileSearch("C:\\Windows", "explorer.exe"); Thread thread = new Thread(searcher); thread.start();
-
等待10秒钟,中断线程:
try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); }
-
运行程序,查看结果。
工作原理
下图展现范例的执行结果。可以看到FileSearch对象结束线程执行,以及当线程检测到已被中断时停止执行。
在范例中,我们使用Java异常来控制线程的中断。当运行范例时,程序遍历文件夹来判断是否存在对应文件。例如,如果进入\b\c\d文件夹,程序将递归三次调用directoryProcess()方法。当检测到线程已被中断,无论递归调用多少次,run()方法都会抛出IterruptedException异常,并且继续执行。
扩展学习
IterruptedException异常是由与并发API相关的Java方法抛出的,例如sleep()。如果线程在休眠的时候被中断(用interrupt()方法),就会抛出这个异常。
更多关注
本章中“中断线程”小节。