Java中的interrupted()和isInterrupted()

目录
  • 1、前言
  • 2、API
  • 3、interrupted()和isInterrupted()区别
    • 3.1 使用方法
      • 方法一
      • 方法二

1、前言

当提及如何终止一个线程时,部分读者通常立马想到的方法肯定是stop(),但是stop()方法并不被推荐使用(很多规范中是禁止使用的),其原因是强制终止一个线程,会导致程序不正常的结束,会出现资源未正确释放、程序结果不正确等等问题。而是否终止一个线程应该把这个控制权转交给当前被终止的线程本身,此时采用的办法就是 ****interrupt()方法来终止,该方法相当于修改一个共享变量的值,当运行中的线程判断当前值为false则继续运行,如果有地方调用当前threadinterrupt()方法,那么这个值将变为true,此时当前线程可以根据这个值的修改来正确的终止线程的运行。

2、API

java.lang.Thread中主要提供了如下与线程中断相关的方法,其具体方法名与主要作用如下表所示。

方法名 方法作用
public void interrupt() 中断此线程
public static boolean interrupted() 测试当前线程是否被中断,该方法会恢复(清除)中断标志
public boolean isInterrupted() 测试当前线程是否被中断,该方法只会获取中断标志,不会恢复(清除)中断标志
private native boolean isInterrupted(boolean ClearInterrupted); interrupted()和isInterrupted()最终调用,该方法是native本地方法,在jvm中具体实现,也是获取线程中断标志真正调用的方法,参数ClearInterrupted意思是是否恢复(清除)中断标志

源码:

/**

 * 中断此线程

 */

public void interrupt() {

    if (this != Thread.currentThread())

        checkAccess();

    synchronized (blockerLock) {

        Interruptible b = blocker;

        if (b != null) {

            interrupt0();           // Just to set the interrupt flag

            b.interrupt(this);

            return;

        }

    }

    interrupt0();

}

/**

 *	测试当前线程是否被中断,返回中断标志

 */

public static boolean interrupted() {

    return currentThread().isInterrupted(true);

}

/**

 *	测试当前线程是否被中断,返回中断标志

 */

public boolean isInterrupted() {

    return isInterrupted(false);

}

/**

 * 线程是否被中断native方法,ClearInterrupted为是否清除中断标志参数

 */

private native boolean isInterrupted(boolean ClearInterrupted);

/**

 *	中断当前线程的native方法

 */

private native void interrupt0();

3、interrupted()和isInterrupted()区别

看了上述API讲述和Thread中的源码,已经清楚interrupted()isInterrupted()的主要区别了

interrupted()为静态方法,isInterrupted()为普通方法

interrupted() 返回中断标志且清除(恢复)中断标志,isInterrupted()仅返回中断标志

3.1 使用方法

我们先验证中断异常响应,通过如下两种方法的使用示例来介绍,注意Runner中的run方法的部分区别

方法一

package com.liziba.p7;

import java.util.concurrent.TimeUnit;

/**

 * <p>

 *      

 * </p>

 *

 * @Author: Liziba

 * @Date: 2021/6/24 21:05

 */

public class ThreadInterruptedDemo { 

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new Runner(), "Thread-01");

        t1.start();

        // 主线程睡眠1秒,保证t1的充分执行

        TimeUnit.SECONDS.sleep(1);

        // 发起中断

        t1.interrupt();

    }

    static class Runner implements Runnable {

        @Override

        public void run() {

            while (!Thread.currentThread().isInterrupted()) {

                System.out.println(Thread.currentThread().getName() + " is running .");

            }

        }

    }

}

输出结果:

可以看到线程在执行数次后终止运行

方法二

package com.liziba.p7;

import java.util.concurrent.TimeUnit;

/**

 * <p>

 *

 * </p>

 *

 * @Author: Liziba

 * @Date: 2021/6/24 21:18

 */

public class ThreadInterruptedDemo {

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new Runner(), "Thread-01");

        t1.start();

        // 主线程睡眠2秒,保证t1的充分执行

        TimeUnit.SECONDS.sleep(1);

        // 发起中断

        t1.interrupt();

    }

    static class Runner implements Runnable {

        @Override

        public void run() {

            while (!Thread.currentThread().isInterrupted()) {

                System.out.println(Thread.currentThread().getName() + " is running .");

                try {

                    // 睡眠2秒,保证主线程发起的中断能被捕获

                    TimeUnit.SECONDS.sleep(2);

                } catch (InterruptedException e) {

                    // 不对中断做任何处理,try住异常,打印

                    e.printStackTrace();

                }

            }

        }

    }

}

输出结果:

可以看到main线程中发起的t1线程中断,被捕获住异常后,未做任何处理,线程继续持续不断的运行

总结上述两种方式:

方法一和方法二,均通过判断Thread.currentThread().isInterrupted()的值来运行run方法中的逻辑,Thread.currentThread().isInterrupted()在线程未中断时返回false,当main线程中执行 t1.interrupt()时,线程t1被中断,Thread.currentThread().isInterrupted()的值变为false;在方法一中,获取到这个变化后直接结束运行;在方法二中,由于sleep()使得线程阻塞会响应中断,但是此时我仅仅catch住异常,并没有对中断做任何处理,这里有个知识点是,线程响应中断抛出异常时,会恢复(清除)中断标志,所以t1.interrupt()对中断标志的修改又被恢复了,程序仍然不断的运行。

接下来我们来验证interrupted()对于中断的标志的清除

package com.liziba.p7;

import java.util.concurrent.TimeUnit;

/**

 * <p>

 *		isInterrupted()

 * </p>

 *

 * @Author: Liziba

 * @Date: 2021/6/24 21:20

 */

public class ThreadInterruptDemo2 {

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new Runner(), "Thread-1");

        thread.start();

        TimeUnit.SECONDS.sleep(2);

        thread.interrupt();

    }

    static class Runner implements Runnable {

        @Override

        public void run() {

            System.out.println(Thread.currentThread().getName() +" interrupted flag is " + Thread.currentThread().isInterrupted());

            while (!Thread.currentThread().isInterrupted()) {

                try {

                    System.out.println(Thread.currentThread().getName() + " is running .");

                    TimeUnit.SECONDS.sleep(1);

                } catch (InterruptedException e) {

                    // 响应中断,抛出异常后中断位置会被复位,自己中断自己

                    Thread.currentThread().interrupt();

                    // 这里调用isInterrupted()获取当前的中断标志

                    System.out.println(Thread.currentThread().getName()

                            +" interrupted flag is " + Thread.currentThread().isInterrupted());

                }

            }

        }

    }

}

输出结果:

这里证明interrupted()不清楚中断标志,线程在获取到 thread.interrupt()发起中断后,执行结束。

将上述catch中的Thread.currentThread().isInterrupted()修改为Thread.interrupted()再次运行

package com.liziba.p7;

import java.util.concurrent.TimeUnit;

/**

 * <p>

 *

 * </p>

 *

 * @Author: Liziba

 * @Date: 2021/6/24 21:23

 */

public class ThreadInterruptDemo2 {

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new Runner(), "Thread-1");

        thread.start();

        TimeUnit.SECONDS.sleep(2);

        thread.interrupt();

    }

    // 区别在catch中

    static class Runner implements Runnable {

        @Override

        public void run() {

            System.out.println(Thread.currentThread().getName() +" interrupted flag is " + Thread.currentThread().isInterrupted());

            while (!Thread.currentThread().isInterrupted()) {

                try {

                    System.out.println(Thread.currentThread().getName() + " is running .");

                    TimeUnit.SECONDS.sleep(1);

                } catch (InterruptedException e) {

                    // 响应中断,抛出异常后中断位置会被复位,自己中断自己

                    Thread.currentThread().interrupt();

                    // 注意区别在这里

                    System.out.println(Thread.currentThread().getName()

                            +" interrupted flag is " + Thread.interrupted());

                }

            }

        }

    }

}

输出结果:

线程也响应到了 thread.interrupt()的中断,但是由于catch中调用了Thread.interrupted(),对中断标志进行了清除,所以!Thread.currentThread().isInterrupted()判断仍然等于true,线程继续不断的运行

看到这里,应该已经理解了这两个方法的主要区别和其使用,最后我们来看下一个源码中的使用案例。我们通过观看AbstractQueuedSynchronizer(AQS)中的await()方法,来看其在源码中的使用。

public final void await() throws InterruptedException {

    // 判断当前线程是否被中断,如果被中断则恢复中断标志

    if (Thread.interrupted())

        throw new InterruptedException();

    Node node = addConditionWaiter();

    int savedState = fullyRelease(node);

    int interruptMode = 0;

    while (!isOnSyncQueue(node)) {

        LockSupport.park(this);

        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)

            break;

    }

    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)

        interruptMode = REINTERRUPT;

    if (node.nextWaiter != null) // clean up if cancelled

        unlinkCancelledWaiters();

    if (interruptMode != 0)

        reportInterruptAfterWait(interruptMode);

}

AbstractQueuedSynchronizer(AQS)源码中使用静态Thread.interrupted(),判断当前线程是否被中断,并恢复中断标志,如果线程已被中断则抛出InterruptedException中断异常。清除标志位的作用就是为了当前线程响应过中断后,再次进入的时候可以进行后续操作。

到此这篇关于Java中的interrupted()isInterrupted()的文章就介绍到这了,更多相关interrupted()和isInterrupted()内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-11-23

JAVA多线程之中断机制stop()、interrupted()、isInterrupted()

一,介绍 本文记录JAVA多线程中的中断机制的一些知识点.主要是stop方法.interrupted()与isInterrupted()方法的区别,并从源代码的实现上进行简单分析. JAVA中有3种方式可以终止正在运行的线程 ①线程正常退出,即run()方法执行完毕了 ②使用Thread类中的stop()方法强行终止线程.但stop()方法已经过期了,不推荐使用 ③使用中断机制 线程正常退出没有什么东东,中断机制下面详细介绍,先看下stop()方法的源代码,关键是源代码上的注释.它解释了为什么s

java isInterrupted()判断线程的实例讲解

1.说明 isInterrupted()可以判断当前线程是否被中断,仅仅是对interrupt()标识的一个判断,并不会影响标识发生任何改变(因为调用interrupt()的时候会设置内部的一个叫interrupt flag的标识). 2.实例 public static void main(String[] args) throws InterruptedException{ Thread thread = new Thread(()->{ while (true){} }); thread.

java中volatile不能保证线程安全(实例讲解)

今天打了打代码研究了一下java的volatile关键字到底能不能保证线程安全,经过实践,volatile是不能保证线程安全的,它只是保证了数据的可见性,不会再缓存,每个线程都是从主存中读到的数据,而不是从缓存中读取的数据,附上代码如下,当synchronized去掉的时候,每个线程的结果是乱的,加上的时候结果才是正确的. /** * * 类简要描述 * * <p> * 类详细描述 * </p> * * @author think * */ public class Volatil

java发送email一般步骤(实例讲解)

java发送email一般步骤 一.引入javamail的jar包: 二.创建一个测试类,实现将要发送的邮件内容写入到计算机本地,查看是否能够将内容写入: public static void main(String[] args) throws Exception { // 1. 创建一封邮件 Properties props = new Properties(); // 用于连接邮件服务器的参数配置(发送邮件时才需要用到) Session session= Session.getDefaul

java对象类型转换和多态性(实例讲解)

对象类型转换 分为向上转型和向下转型(强制对象转型). 向上转型是子对象向父对象转型的过程,例如猫类转换为动物类:向下转型是强制转型实现的,是父对象强制转换为子对象. 这和基础数据类型的转换是类似的,byte在需要时会自动转换为int(向上转型),int可以强制转型为byte(向下转型). 对于对象转型来说, 向上转型后子对象独有的成员将不可访问 . 意思是,在需要一只动物时,可以把猫当作一只动物传递,因为猫继承自动物,猫具有动物的所有属性.但向上转型后,猫不再是猫,而是被当作动物看待,它自己独

java 动态生成SQL的实例讲解

代码如下: /** * 动态生成SQ及SQL参数L * @param ve 接收到的消息的CHGLIST * @param paramList MQ消息中的SQL参数 * @param t 泛型对象 * @param table 数据表 * @param list 可执行SQL语句集合 * @return */ public <T> String updateSqlAndParamList(Vector<String> ve,List<String> paramList

JAVA超级简单的爬虫实例讲解

爬取整个页面的数据,并进行有效的提取信息,注释都有就不废话了: public class Reptile { public static void main(String[] args) { String url1=""; //传入你所要爬取的页面地址 InputStream is=null; //创建输入流用于读取流 BufferedReader br=null; //包装流,加快读取速度 StringBuffer html=new StringBuffer(); //用来保存读取页

Java成员变量的隐藏(实例讲解)

一.如果子类与父类中有一个相同名称的成员变量,那么子类的成员变量会不会覆盖父类的成员变量?我们看下在的例子: public class A { public int x=10; } public class B extends A { public int x=20; } public class C { public static void main(String[] args) { A a=new B(); System.out.println(a.x); //1 B b=new B();

Java分页查询--分页显示(实例讲解)

当数据库中数据条数过多时,一个页面就不能显示,这是要设置分页查询,首先要使用的是数据库sql语句的limit条件实现分组查询 sql语句大概形式为: select * from table limit 开始索引,显示条数 用该语句就会实现分块查询,并且每页显示固定条数. 首先要实现后台分页,我们需要知道它有多少页,每页有多少行,这就需要知道一共多少行,调用sql语句时还需要知道每一页的开始索引,开始索引是根据当前页数算出来的,所以还需要知道当前页数,查询后会返回一个列表存储当前页数据.将这些属性

利用Java理解sql的语法(实例讲解)

select 相当于 for 循环 select id from IDArray LinkedList a = new LinkedList(); for ( int i=0 ; i<tableA.length ; i++){ a.add(IDArray.get("id" ) ); } return a; 当执行子查询时,可以理解为 select id, ( select name from nameArray) as names ,from Idarray LinkedList

java RMI详细介绍及实例讲解

java本身提供了一种RPC框架--RMI(即RemoteMethodInvoke远程方法调用),在编写一个接口需要作为远程调用时,都需要继承了Remote,Remote接口用于标识其方法可以从非本地虚拟机上调用的接口,只有在"远程接口"(扩展java.rmi.Remote的接口)中指定的这些方法才可远程使用,下面通过一个简单的示例,来讲解RMI原理以及开发流程: 为了真正实现远程调用,首先创建服务端工程rmi-server,结构如下: 代码说明: 1.User.java:用于远程调用

java 多线程-线程通信实例讲解

线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 通过共享对象通信 忙等待 wait(),notify()和 notifyAll() 丢失的信号 假唤醒 多线程等待相同信号 不要对常量字符串或全局对象调用 wait() 通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值.线程 A 在一个同步块里设置 boolean 型成员变量 hasDataToProcess 为 true,线程 B 也在同步块里读取 hasDataToProc