首发于程序生涯
java中断详细介绍及其对各种线程状态的影响分析

java中断详细介绍及其对各种线程状态的影响分析

最近在复盘java并发的知识,借这篇文章总结下java的线程状态以及各状态下的中断影响。

中断简介

首先来看几个常用的中断Api,在此之前我们先来看一个本地方法

private native boolean isInterrupted(boolean ClearInterrupted);

这个本地方法是我们接下来要说的Api的底层关键实现,返回该线程中断标志位是否被标记。该方法中的参数ClearInterrupted,如果是true,表示会清除中断标志位,即调用后中断标志位由true变为false;如果是false表示不清除中断标志位

接着来看3个常用的中断Api

public void interrupt() 设置当前线程的中断标志位,仅此而已

public boolean isInterrupted() 判断当前线程中断标志位是否被标记为中断,不会清除标志位

public boolean isInterrupted() {
        return isInterrupted(false);
}

可以看到底层就是调用的我们上边说过的本地方法,所以该方法不会清除标志位

public static boolean interrupted() 这是一个静态方法,返回当前线程是否标记中断,同时清除标志位

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

底层还是那个本地方法,不过这里标记了true,所以会清除标志位。同时需要特别主要注意的是,这里有一个currentThread(),这个方法返回的是调用这个方法时所在的线程体,而不是调用该方法的线程实例。

测试实例

thread.start();
thread.interrupt();
System.out.println(thread.isInterrupted());
System.out.println(thread.isInterrupted());

Thread.currentThread().interrupt();
System.out.println(Thread.interrupted());
System.out.println(Thread.interrupted());
true
true
true
false

可以看到结果验证了我们所说的,isInterrupted()不会清楚中断标志位,所以前两个返回true,随后将当前线程设置中断,第一次调用Thread.interrupted()返回true,第二次返回false,即中断标志位被清除。

接着来看下在各个线程状态,中断带来的影响

RUNNABLE

public static void main(String[] args) {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while(true);
            }
        },"test");
        thread.start();
        System.out.println(thread.getName()+" "+thread.getState());
        thread.interrupt();
        System.out.println(thread.isInterrupted());
        System.out.println(thread.getName()+" "+thread.getState());
    }
test RUNNABLE
true
test RUNNABLE

可以看到,中断对RUNNABLE的test线程就只是将中断标志位置为true,仅此而已。不会抛出异常,线程状态也不变。

NEW | TERMINATEDE

public static void main(String[] args) {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while(true);
            }
        },"test");
        System.out.println(thread.getName()+" "+thread.getState());
        thread.interrupt();
        System.out.println(thread.isInterrupted());
        System.out.println(thread.getName()+" "+thread.getState());
    }
test NEW
false
test NEW

还是上一段代码,去掉start,此时test线程是NEW状态,同时中断标志位为false,可见中断对此状态的线程可以说完全不起作用。

WAITING

public class Twf implements  Runnable {
    @Override
    public void run() {
        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("interrupted");
                System.out.println(Thread.currentThread().isInterrupted());
            }
        }
    }
    public static void main(String[] args) {
        Twf twf=new Twf();
        Thread thread1=new Thread(twf,"test1");
        thread1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(thread1.getName()+" "+thread1.getState());
        thread1.interrupt();
    }
}
test1 WAITING
interrupted
false

可以看到,waiting状态的线程对中断很敏感,中断会抛出异常同时会清除中断标志位。同时别忘了,wait需要和synchronized配合使用! 至于为什么,看下一篇吧

Blocked

public class Twf implements  Runnable {

     static  synchronized  void test(){
        while(true);
    }
    @Override
    public void run() {
        test();
    }
    public static void main(String[] args) {
        Twf twf=new Twf();
        Thread thread1=new Thread(twf,"test1");
        Thread thread2=new Thread(twf,"test2");
        thread1.start();
        // 睡眠1s
        thread2.start();
       // 睡眠1s
        System.out.println(thread2.getName()+" "+thread2.getState());
        thread2.interrupt();
        System.out.println(thread2.getName()+" "+thread2.getState());
        System.out.println(thread2.isInterrupted());
    }
}
test2 BLOCKED
test2 BLOCKED
true

可以看到中断对时间片Block也没有什么影响,只会把中断标志位置为true。

总结

以前学单片机总认为中断就是系统停下来去干别的事情,java中断仅仅是设置中断标记位。对于NEW|TERMINATED 线程,终端完全不起作用;对于RUNNABLE或者BLOCKED线程,只会将中断标志位设为true;WAITING线程对中断较为敏感,会抛出异常,同时会将中断标志位清除变为false。java中的中断设置标志位,接着的事情就留给程序员,根据中断这一条件去执行别的逻辑抑或是不管。

公众号:*程序员二狗*

交流学习*

发布于 2019-10-24 16:37