三、中断一个线程

  一个拥有多个线程的Java程序要结束,需要满足两个条件之一:一是所有的非后台线程都执行结束了;二是某个线程执行了 System.exit() 方法。当你想要终结一个运行中的Java程序或者程序的用户想要取消一个线程正在执行的任务时,你都需要结束一个线程。

  Java提供中断机制来表明我们想要终止一个线程。这个机制的核心是线程必须要检查自己是否被中断,而且线程自己决定是否响应中断请求。线程可以忽略该中断请求而继续执行。

  在本秘诀中,我们将开发一个程序,这个程序创建线程,5秒后使用中断机制来结束线程。

public class Main {
    public static void main(String[] args) {
        Thread task = new PrimeGenerator();
        task.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        task.interrupt();
    }
}

public class PrimeGenerator extends Thread {

    @Override
    public void run() {
        long number = 1L;
        while (true) {
            if (isPrime(number)) {
                System.out.printf("Number "+ number +" is Prime");
            }

            if (isInterrupted()) {
                System.out.printf("The Prime Generator has been Interrupted");
                return;
            }
            number++;
        }
    }

    private boolean isPrime(long number) {
        if (number <= 2) {
            return true;
        }
        for (long i = 2; i < number; i++) {
            if ((number % i) == 0) {
                return false;
            }
        }
        return true;
    }
}

  在 Thread 类中有一个 boolean 类型的属性来表明该类对应的线程是否被中断。通过调用 Thread 对象的 interrupt() 方法,设置其对应的线程被中断。而 isInterrupted() 方法用来返回对应线程是否被中断的状态。

  Thread 类还有一个静态方法 interrupted() 同样可以返回所在线程是否被中断的状态。但是该方法还有一个副作用:就是把线程的被中断状态重设为 false。

  线程可以忽略其被中断的状态,但这通常不是好的编程习惯。

四、控制线程的中断状态

  在上一个秘诀中,你学习了如何去中断一个线程和如何去控制线程的中断状态。如果你要中断执行的只是一个简单的线程,那么上一个秘诀就足够了。但是,如果该线程实现了一个分成多个方法的复杂算法,或者它含有实现了递归算法的方法,我们应该使用一种更好的机制去该线程的中断状态。为此,Java提供了 InterruptedException。当你在 run() 方法里发现了线程被中断时,你可以抛出并捕获该异常。

  在本秘诀中,我们的线程在目录和其子目录中来寻找含有特定名称的文件,这个程序展示如何使用 InterruptedException 来控制线程的中断。

public class FileSearch implements Runnable{
    private String initPath;
    private String 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());
            }
        }
    }

    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();
        }
    }

    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();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        FileSearch search = new FileSearch("C:\\", "autoexec.bat");
        Thread thread = new Thread(search);
        thread.start();

        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        thread.interrupt();
    }
}

  在这个例子中,我们使用异常机制来达到终止线程运行的目的。你运行此示例程序,程序开始遍历目录并查找特定的文件。一旦线程检查到自己被中断了,它就抛出 InterruptedException 异常,继续执行 run() 方法的代码,多层的递归调用对结果没实质影响。

  Java并发API中的 sleep() 方法也有可能抛出 InterruptedException异常。

  笔者总结:本秘诀本质还是线程自己检查是否被中断,发现被中断后,通过抛出异常的方式直接跳转到了异常捕获代码处,是否多层递归对此异常跳转机制没影响。

  重要:本系列翻译文档也会在本人的微信公众号(此山是我开)第一时间发布,欢迎大家关注。

Java 7 Concurrency Cookbook 翻译 第一章 线程管理之二的更多相关文章

  1. Java 7 Concurrency Cookbook 翻译 第一章 线程管理之一

    一.简介 在计算机的世界里,当我们谈论并发时,我们指的是一系列的任务同时运行于一个计算机中.这里说的同时运行,在计算机拥有多于一个处理器或者是一个多核处理器的时候才是真正的同时,在计算机只拥有单核处理 ...

  2. Java 7 Concurrency Cookbook 翻译 第一章 线程管理之六

    十一.处理线程组中的未控制异常 每种编程语言一个很重要的特性就是其所提供的用来处理程序中错误情况的机制.Java语言和其他的现代语言一样,是提供了异常机制来处理对象程序中的错误.Java提供了很多的类 ...

  3. Java 7 Concurrency Cookbook 翻译 第一章 线程管理之五

    九.使用线程本地变量 一个并发程序的最关键特征就是共享数据.这个特性在那些继承了 Thread 类或者 实现了 Runnable 接口的对象上显得更加重要. 如果你创建一个实现了 Runnable 接 ...

  4. Java 7 Concurrency Cookbook 翻译 第一章 线程管理之四

    七.创建和运行一个后台线程 Java中有一种特别的线程叫做 deamon(后台) 线程.这类线程具有非常低的权限,并且只有在同一个程序中没有其他的正常线程在运行时才会运行.注意:当一个程序中只剩下后台 ...

  5. Java 7 Concurrency Cookbook 翻译 第一章 线程管理之三

    五.睡眠和唤醒一个线程 有时,你会想要在一段特定的时间后再去中断线程的运行.举个例子,程序中的一个线程每一分钟检查一次传感器的状态,剩余的时间,线程应该处于空闲的状态.在这段空闲时间里,线程不会使用计 ...

  6. Java 7 Concurrency Cookbook 翻译 序言

    在日常的Java代码开发过程中,很难免地有对多线程的需求,掌握java多线程和并发的机制也是Java程序员写出更健壮和高效代码的基础.笔者找寻国内已出版的关于Java多线程和并发的的中文书籍和翻译书籍 ...

  7. java的优点和误解 《java核心技术卷i》第一章

    <java核心技术卷i>第一章主要内容包括三点: 1:Java白皮书的关键术语:描述Java的十一个关键字: 2:Java applet 3 :关于Java的常见误解   1:第一章:Ja ...

  8. web前端学习python之第一章_基础语法(二)

    web前端学习python之第一章_基础语法(二) 前言:最近新做了一个管理系统,前端已经基本完成, 但是后端人手不足没人给我写接口,自力更生丰衣足食, 所以决定自学python自己给自己写接口哈哈哈 ...

  9. Android线程管理(二)——ActivityThread

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

随机推荐

  1. 9 HTML&JS等前端知识系列之Ajax post请求带有token向Django请求

    我们 在母板上写入这段代码: <script type="text/javascript"> // 个人定义大函数,不是重点,可以忽略 $(document).read ...

  2. 忘记常访问网站密码怎么办?教你如何查看浏览器已保存的密码,如何简单查看Chome浏览器保存的密码?

    利用场景: 同事或朋友外出有事,电脑未锁屏离开座位.可以利用这一间隙,查看Ta在Chrome浏览器上保存的账号密码 查看逻辑: 当我们要查看Chrome浏览器上保存的密码时,点击显示,会弹出一个对话框 ...

  3. apache无法正常启动,80端口被占用的解决方法

    apache无法正常启动,80端口被占用的解决方法 网上的方法: 仔细查看提示: make_sock: could not bind to address 0.0.0.0:80 恍然大悟,计算机上安装 ...

  4. 4个mysql客户端工具的比较

    mysql是我以前学习和练习所使用的数据,现在在工作中也在使用,之前公司里用oracle,我在做自己的东西的时候觉得用oracle太不方便,于是就找了mysql(当时也考虑过sqlserver,觉得还 ...

  5. mysql循环获取结果集

    do { MYSQL_RES* res = mysql_store_result(con); ) { MYSQL_ROW row; if (row = mysql_fetch_row(res)) { ...

  6. Android学习笔记——xml

    转自http://blog.csdn.net/sam_zhang1984 解析 XML 有两种方式: SAX 和 DOM .它们各有利弊. DOM 是把 XML 文档全部装载到内存中,然后当成一树进行 ...

  7. C++ 生成 dll 和调用 dll 的方法实例(转)

    1)生成dll 建立两个文件 xxx.h , xxx.cpp xxx.h内容如下: #ifdef BUILD_XXX_DLL#define EXPORT __declspec(dllexport)#e ...

  8. Django笔记-常见错误整理

    1.csrf错误 解决方法:在settings.py里注释掉相关内容即可 MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.Sess ...

  9. ImageTragick Exploit & Fix

    ImageMagick是一款广泛流行的图像处理软件,有无数的网站(国内国外都有)使用它来进行图像处理,本周二,ImageMagick披露出了一个严重的0day漏洞,此漏洞允许攻击者通过上传恶意构造的图 ...

  10. yii2 小技巧

    参考地址:http://www.cnblogs.com/sandea/p/5714830.html 1.不通过日志获取AR执行的原生SQL语句和打印变量数据 $query = User::find() ...