java 中断线程的几种方式 interrupt()详解

中断

  中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序。虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果。你最好还是牢记以下的几点告诫。

  首先,忘掉Thread.stop方法。虽然它确实停止了一个正在运行的线程,然而,这种方法是不安全也是不受提倡的,这意味着,在未来的JAVA版本中,它将不复存在。

如何安全的结束一个正在运行的线程

 Thread类相关的方法

  java.lang.Thread类包含了一些常用的方法,如:start(), stop(), stop(Throwable) ,suspend(), destroy() ,resume()。通过这些方法,我们可以对线程进行方便的操作,但是这些方法中,只有start()方法得到了保留。

  在JDK帮助文档以及Sun公司的一篇文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》中都讲解了舍弃这些方法的原因。

  简单来说是因为:使用stop方法虽然可以强行终止正在运行或挂起的线程,但使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。

 那么,我们究竟应该如何停止线程呢?

1、任务中一般都会有循环结构,只要用一个标记控制住循环,就可以结束任务。

2、如果线程处于了冻结状态,无法读取标记,此时可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格。

(一):使用退出标志

  当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的,如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。

  在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。

public class test1 {

    public static volatile boolean exit =false;  //退出标志

    public static void main(String[] args) {
        new Thread() {
            public void run() {
                System.out.println("线程启动了");
                while (!exit) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程结束了");
            }
        }.start();

        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        exit = true;//5秒后更改退出标志的值,没有这段代码,线程就一直不能停止
    }
}

(二):使用 interrupt 方法

  Thread.interrupt()方法: 作用是中断线程。将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。它并不像stop方法那样会中断一个正在运行的线程 

  interrupt()方法只是改变中断状态,不会中断一个正在运行的线程。需要用户自己去监视线程的状态为并做处理。支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。这一方法实际完成的是,给受阻塞的线程发出一个中断信号,这样受阻线程检查到中断标识,就得以退出阻塞的状态。

更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,此时调用该线程的interrupt()方法,那么该线程将抛出一个 InterruptedException中断异常(该线程必须事先预备好处理此异常),从而提早地终结被阻塞状态。如果线程没有被阻塞,这时调用 interrupt()将不起作用,直到执行到wait(),sleep(),join()时,才马上会抛出 InterruptedException。

 使用 interrupt() + InterruptedException来中断线程

  线程处于阻塞状态,如Thread.sleep、wait、IO阻塞等情况时,调用interrupt方法后,sleep等方法将会抛出一个InterruptedException:

public static void main(String[] args) {
        Thread thread = new Thread() {
            public void run() {
                System.out.println("线程启动了");
                try {
                    Thread.sleep(1000 * 100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程结束了");
            }
        };
        thread.start();

        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();//作用是:在线程阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
    }

 使用 interrupt() + isInterrupted()来中断线程  

  this.interrupted():测试当前线程是否已经中断(静态方法)。如果连续调用该方法,则第二次调用将返回false。在api文档中说明interrupted()方法具有清除状态的功能。执行后具有将状态标识清除为false的功能。

  this.isInterrupted():测试线程是否已经中断,但是不能清除状态标识。

public static void main(String[] args) {
        Thread thread = new Thread() {
            public void run() {
                System.out.println("线程启动了");
                while (!isInterrupted()) {
                    System.out.println(isInterrupted());//调用 interrupt 之后为true
                }
                System.out.println("线程结束了");
            }
        };
        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        System.out.println("线程是否被中断:" + thread.isInterrupted());//true
    }

。。。。。。。。。。

来一个综合的例子:

public class test1 {

    static volatile boolean flag = true;

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("开始休眠");
                try {
                    Thread.sleep(100 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("结束休眠,开始死循环");
                while (flag) {
                }
                System.out.println("------------------子线程结束------------------");
            }
        });
        thread.start();

        Scanner scanner = new Scanner(System.in);
        System.out.println("输入1抛出一个中断异常,输入2修改循环标志位,输入3判断线程是否阻塞,输入其他结束Scanner\n");
        while (scanner.hasNext()) {
            String text = scanner.next();
            System.out.println("你输入了:" + text + "\n");
            if ("1".equals(text)) {
                thread.interrupt();
            } else if ("2".equals(text)) {
                flag = false; //如果不设为false,主线程结束后子线程仍在运行
            } else if ("3".equals(text)) {
                System.out.println(thread.isInterrupted());
            } else {
                scanner.close();
                break;
            }
        }
        System.out.println("------------------主线程结束------------------");
    }
}

不能结束的情况

注意下面这种是根本不能结束的情况!

public class Test {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            public void run() {
                System.out.println("线程启动了");
                while (true) {//对于这种情况,即使线程调用了intentrupt()方法并且isInterrupted(),但线程还是会继续运行,根本停不下来!
                    System.out.println(isInterrupted());//调用interrupt之后为true
                }
            }
        };
        thread.start();
        thread.interrupt();//注意,此方法不会中断一个正在运行的线程,它的作用是:在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
        while (true) {
            System.out.println("是否isInterrupted:" + thread.isInterrupted());//true
        }
    }
}

关于interrupted()和isInterrupted()方法的注意事项说明

  interrupted()是静态方法:内部实现是调用的当前线程的isInterrupted(),并且会重置当前线程的中断状态。

    测试当前线程是否已经中断(静态方法)。返回的是上一次的中断状态,并且会清除该状态,所以连续调用两次,第一次返回true,第二次返回false。

  isInterrupted()是实例方法,是调用该方法的对象所表示的那个线程的isInterrupted(),不会重置当前线程的中断状态

    测试线程当前是否已经中断,但是不能清除状态标识。

测试方法验证:

1:

  第一个红框中断的线程是我们自己创建的thread线程,我调用的interrupted(),由上面源码可知是判断当前线程的中断状态,当前线程是main线程,我根本没有中断过main线程,所以2次调用均返回“false”

2:

  第一个红框中断的线程是当前线程(main线程),我调用的interrupted(),由上面源码可知是判断当前线程的中断状态,当前线程是main线程,所以第1次调用结果返回“true”,因为我确实中断了main线程

  由源码可知interrupted()调用的是isInterrupted(),并会重置中断状态,所以第一次调用之后把中断状态给重置了,从中断状态重置为非中断状态,所以第2次调用的结果返回“false”

3:

  第一个红框中断的线程是我们自己创建的thread线程,我调用的isInterrupted(),由上面源码可知是判断执行该方法的对象所表示线程的中断状态,也就是thread引用所表示的线程的中断状态,所以第1次调用结果返回“true”,

  由源码可知isInterrupted()不会重置中断状态,所以第一次调用之后没有把中断状态给重置(从中断状态重置为非中断状态),所以第2次调用的结果还返回“true”

到此这篇关于java 中断线程的几种方式 interrupt()的文章就介绍到这了,更多相关java 中断线程interrupt()内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入分析JAVA 多线程--interrupt()和线程终止方式

    一.interrupt() 介绍 interrupt() 定义在 Thread 类中,作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的 interrupt() 方法时,会通过 checkAccess() 检查权限.这有可能抛出 SecurityException 异常. 如果本线程是处于阻塞状态:调用线程的 wait() , wait(long) 或 wait(long, int) 会让它进入等待(阻塞)状态,或者调用线程的 join(),join(long),join(lon

  • Java多线程之Interrupt中断线程详解

    一.测试代码 https://gitee.com/zture/spring-test/blob/master/multithreading/src/test/java/cn/diswares/blog/InterruptTests.java 二.测试 为了方便理解简介中 interrupt 的概念, 写个 DEMO 测试一下 /** * 调用 interrupt 并不会影响线程正常运行 */ @Test public void testInvokeInterrupt() throws Inter

  • Java中断线程的方法

    使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回.这里需要注意的是,如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行. 下面一段代码演示了休眠线程的中断: public class SleepInterrupt extends Object implements Runnable{ public void run()

  • Java如何使用interrupt()终止线程

    一.interrupt() 说明 interrupt()的作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限.这有可能抛出SecurityException异常. 如果本线程是处于阻塞状态:调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sl

  • Java多线程之中断线程(Interrupt)的使用详解

    interrupt方法 interrupt字面上是中断的意思,但在Java里Thread.interrupt()方法实际上通过某种方式通知线程,并不会直接中止该线程.具体做什么事情由写代码的人决定,通常我们会中止该线程. 如果线程在调用Object类的wait().wait(long)或wait(long, int)方法,或者该类的 join() .join(long) .join(long, int) .sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态

  • Java interrupt()方法使用注意_动力节点Java学院整理

    程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误. 在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程. 背景 中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作.线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序.虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果.你最好还是牢记以下的几点告诫. 首先,忘掉Thre

  • interrupt()和线程终止方式_动力节点Java学院整理

    中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序本身.线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true).它并不像stop方法那样会中断一个正在运行的线程. 判断线程是否被中断 判断某个线程是否已被发送过中断请求,请使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位

  • java 中断线程的几种方式 interrupt()详解

    中断 中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作.线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序.虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果.你最好还是牢记以下的几点告诫. 首先,忘掉Thread.stop方法.虽然它确实停止了一个正在运行的线程,然而,这种方法是不安全也是不受提倡的,这意味着,在未来的JAVA版本中,它将不复存在. 如何安全的结束一个正在运行的线程 Thread类相关的方

  • java 实现websocket的两种方式实例详解

    一.介绍 1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket 2.tomcat的方式需要tomcat 7.x,JEE7的支持. 3.spring与websocket整合需要spring 4.x,并且使用了socketjs,对不支持websocket的浏览器可以模拟websocket使用 二.方式一:tomcat 使用这种方式无需别的任何配置,只需服务端一个处理类, 服务器端代码 package com.Socket; import java.io

  • C#开启线程的四种方式示例详解

    一.异步委托开启线程 public static void Main(string[] args){ Action<int,int> a=add; a.BeginInvoke(3,4,null,null);//前两个是add方法的参数,后两个可以为空 Console.WriteLine("main()"); Console.ReadKey(); } static void add(int a,int b){ Console.WriteLine(a+b); } 运行结果: 如

  • java 创建线程的四种方式

    1.继承Thread类方式 这种方式适用于执行特定任务,并且需要获取处理后的数据的场景. 举例:一个用于累加数组内数据的和的线程. public class AdditionThread extends Thread { private int sum = 0; private int[] nums; ​ public AdditionThread(int[] nums, String threadName) { super(threadName); this.nums = nums; } ​

  • 关于Java创建线程的2种方式以及对比

    目录 1. 继承Thread类 2. 实现Runnable接口: 创建线程的两种方式对比: 线程的完整生命周期: 总结 Java中两种创建线程的方式: 1. 继承Thread类 重写run()方法 new一个线程对象 调用对象的start()启动线程 class Handler extends Thread{ public void run(){ //重写run()方法 } public static void main(String[] args){ Thread thread=new Han

  • Java 高并发的三种实现案例详解

    提到锁,大家肯定想到的是sychronized关键字.是用它可以解决一切并发问题,但是,对于系统吞吐量要求更高的话,我们这提供几个小技巧.帮助大家减小锁颗粒度,提高并发能力. 初级技巧-乐观锁 乐观锁使用的场景是,读不会冲突,写会冲突.同时读的频率远大于写.  悲观锁的实现: 悲观的认为所有代码执行都会有并发问题,所以将所有代码块都用sychronized锁住 乐观锁的实现: 乐观的认为在读的时候不会产生冲突为题,在写时添加锁.所以解决的应用场景是读远大于写时的场景. 中级技巧-String.i

  • Android 打包三种方式实例详解

     Android 打包三种方式实例详解 前言: 现在市场上很多app应用存在于各个不同的渠道,大大小小几百个,当我们想要在发布应用之后统计各个渠道的用户下载量,我们就要进行多渠道打包. 01.应用的打包签名什么是打包? 打包就是根据签名和其他标识生成安装包. 签名是什么? 1.在android应用文件(apk)中保存的一个特别字符串 2.用来标识不同的应用开发者:开发者A,开发者B 3.一个应用开发者开发的多款应用使用同一个签名 就好比是一个人写文章,签名就相当于作者的署名. 如果两个应用都是一

  • Spring加载properties文件的两种方式实例详解

    在项目中如果有些参数经常需要修改,或者后期可能需要修改,那我们最好把这些参数放到properties文件中,源代码中读取properties里面的配置,这样后期只需要改动properties文件即可,不需要修改源代码,这样更加方便.在Spring中也可以这么做,而且Spring有两种加载properties文件的方式:基于xml方式和基于注解方式.下面分别讨论下这两种方式. 1. 通过xml方式加载properties文件 我们以Spring实例化dataSource为例,我们一般会在beans

  • Java编程中的4种代码块详解

    在Java编程中,代码块就是指用"{}"括起来的代码.下面看一下这四种代码块. 1.普通代码块 就是指类中方法的方法体. public void xxx(){ //code } 2.构造块 下面用"{}"括起来的代码片段,构造块在创建对象时会被调用,每次创建对象时都会被调用,并且优先于类构造函数(包括有参和无参的)执行. 构造块中定义的变量是局部变量. public class Client { {//构造代码块 System.out.println("执

  • QT实现多线程两种方式案例详解

    Qt线程 Qt4.7之前版本处理步骤 1.自定义一个类,继承于QThread. class MyThread:public QThread{ public: vid run(); //虚函数 线程处理函数(和主线程不在同一个线程) signals: void isDone(); //信号 线程执行完发送 } void MyThread::run() { // 实现 -- 复杂的处理过程 emit isDome; // 发送线程 }; 2.定义线程 MyThread thread; 3.开启线程

随机推荐