控制线程的中断

上一节所说的中断机制能用在简单的场景。但应用在复杂场景(如算法较复杂需要分解成多个方法、有递归调用等情况)时,有一个更好的机制。 您可抛出 InterruptedException 异常并在 run() 方法中捕获此异常。

任务

实现一个线程在目录及其所有子目录中查找有指定文件名的文件。

实现

  • 线程类 (FileSearch)

    • String 类型的私有变量 initPath 和 fileName 及构造函数。
      表示在 initPath 目录及其所有子目录下搜索文件名为 fileName 的文件。
        private String initPath;
        private String fileName;
    
        public FileSearch(String initPath, String fileName) {
            this.initPath = initPath;
            this.fileName = fileName;
        }
    
    • 在 run 方法中调用 directoryProcess 方法搜索目录并捕捉 InterruptedException
        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 方法查找文件并递归在子目录中查找。处理完后检查线程是否被中断,如果被中断则抛出 InterruptedException 异常。
        private void directoryProcess(File file) throws InterruptedException {
            File list[] = file.listFiles();
            if (list != null) {
                for (File aList : list) {
                    if (aList.isDirectory()) {
                        directoryProcess(aList);
                    } else {
                        fileProcess(aList);
                    }
                }
            }
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
        }
    
    • 在 fileProcess 方法中比较文件名。比较完后检查线程是否被中断,如果被中断则抛出 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)

    • 创建并初始化 FileSearch 类对象,创建线程并启动
        FileSearch searcher = new FileSearch("C:\\", "autoexec.bat");
        Thread thread = new Thread(searcher);
        thread.start();
    
    • 等待 10 秒后中断线程
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        thread.interrupt();
    

工作原理

在此例子中,我们使用Java异常来控制线程的中断。当此案例运行时,程序开始遍历文件夹检查是否包含指定文件名的文件。 当进入到 \b\c\d 文件夹时,将有3个processDirectory方法的递归调用。 当它检测到被中断,不管递归了多少层,它都将抛出 InterruptedException 异常并继续在 run 方法中执行。

了解更多

InterruptedException 异常在与并发 API (如 sleep() )相关的Java方法中抛出。