线程方法interrupt/isInterrupted/interrupted源码分析

众所周知,interrupt是线程中断相关的方法,那么interrupt在底层又究竟干了什么呢?

本章内容要探究的问题:

1.interrupt究竟做了什么?

2.interrupt真的中断了线程吗?

3.isInterrupted与interrupted有什么区别?

好了,接下来进入源码...

一、interrupt

调用interrupt方法,可以看到,除了检查当前线程和自定义扩展线程中断情况外,就直接调用了interrupt0方法,该方法是native的。

在c++中,调用的是jvm.cpp的JVM_Interrupt方法;(图1-1)

紧接着调用的线程的interrupt方法。(图1-2)

  (图1-1)

  (图1-2)

重点来了...

在interrupt方法中,做了两件事情 (图1-3)

1.设置线程中断状态为true;

2.唤醒线程;

在唤醒线程时,有多种情况:如果线程正在sleep状态时;如果线程是调用unsafe.park方法时;如果线程是在synchronized代码块中调用wait时,都将唤醒该线程。

  (图1-3)

至此,interrupt方法结束;在源码中,interrupt方法设置了中断状态,然后唤醒线程;

与其说是中断线程,不如说是中断线程所处的状态,让其回归正常,比如线程处于sleep/wait/park状态,将其唤醒。

二、isInterrupted与interrupted

isInterrupted方法,最终调用的是isInterrupted(booloean clearInterrupter)方法,传参为false;

interrupted方法,最终调用的是isInterrupted(booloean clearInterrupter)方法,传参为true;

两个方法只是参数不同而已 (图2-1)...

isInterrupte后的isInterrupted为native方法,接下来又到快乐的从c++世界了...

在c++中,对应的是jvm.cpp的JVM_IsInterrupted方法,

  (图2-1)

进入其中,在方法中最终又调用了线程的is_interrupted方法,并把java的参数代入其中(图2-2);

 (图2-2)

重点逻辑:

在此方法中(图2-3),获取到线程的中断状态,然后 判断是否为已中断(中断标记为true),并且是否清除为true(就是java传入的参数),如果满足条件,则清除中断标记,设置为false,最后返回之前查询的中断状态;由此可知,isInterrupted与interrupted都是获取线程的中断状态,区别在于interrupted获取到为中断状态之后,会清除中断状态!

  (图2-3)

回到本章开头的提问:

1.interrupt究竟做了什么?做了两件事情1.设置线程中断标记为true,然后唤醒线程。

2.interrupt真的中断了线程吗?没有做中断线程的事情,而是唤醒线程!

3.isInterrupted与interrupted有什么区别?都是获取线程的中断状态,而interrupted获取之后会清除线程中断状态。

最后,附上本人的测试用例

测试1:放开注释1,主线程死循环打印日志,每次休眠一秒,t1线程设置主线程中断;结果:主线程执行结束,休眠状态被中断,抛出线程中断异常,可在catch中捕获异常。

测试2:放开注释2,主线程先进行park挂起,t1线程设置主线程中断;结果:主线程被唤醒继续执行,打印输入日志。

测试3:放开注释3,主线程调用wait进行挂起,t1线程设置主线程中断;结果:主线程执行结束,挂起状态被中断,线程抛出中断异常,可在catch中捕获。

测试4:放开注释4,先让t1线程设置主线程中断,分别调用isInterrupted和interrupted方法;结果:isInterrupted查询线程状态,interrupted查询线程状态并清除了线程状态

/**
 * @author : ZPF
 * @date : 2022-06-21 09:51:57
 * @description : 测试线程的Interrupt方法
 * 在jvm源码中,interrupt做了两件事情:
 * 1.设置中断标记为true
 * 2.唤醒线程unpark(唤醒Thread.sleep/Unsafe.park/synchronized())
 * <p>
 * Thread.currentThread().isInterrupt() 方法:查询线程是否为中断状态
 * Thread.interrupted() 方法:查询线程是否为中断状态  并还原  还原为false
 */
public class TestInterrupt {

    private final static Object OBJ = new Object();

    public static void main(String[] args) {

        Thread mainThread = Thread.currentThread();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 thread start...");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mainThread.interrupt();//设置为中断状态 唤醒线程
                System.out.println("t1 thread end...");
            }
        }, "t1");
        t1.start();

        //1.sleep方法会触发唤醒线程
//        while (true) {
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {//抛出中断异常  当线程在sleep时调用interrupt 抛出
//                e.printStackTrace();
//                System.out.println("catch InterruptedException...");
//                break;
//            }
//            System.out.println("main thread running...");
//        }

        //2.unsafe.park方法会触发唤醒线程
//        Unsafe unSafe = getUnSafe();
//        System.out.println("main thread running start...");
//        unSafe.park(false, 0L);
//        System.out.println("main thread running end...");

        //synchronized中会触发唤醒线程
//        synchronized (OBJ) {
//            System.out.println("main thread wait start...");
//            try {
//                OBJ.wait();
//            } catch (InterruptedException e) {//抛出中断异常  当线程在wait时调用interrupt 抛出
//                e.printStackTrace();
//                System.out.println("catch InterruptedException...");
//            }
//            System.out.println("main thread wait end...");
//        }

        //4.isInterrupted与interrupted区别
//        sleep(4000);
//        boolean interrupted = mainThread.isInterrupted();//查询线程中断状态
//        System.out.println("main interrupted1: " + interrupted);      //true
//        interrupted = mainThread.isInterrupted();
//        System.out.println("main interrupted2: " + interrupted);      //true
//
//        interrupted = Thread.interrupted(); //查询线程中断状态 并还原 还原为false
//        System.out.println("main interrupted3: " + interrupted);      //true
//        interrupted = Thread.interrupted();
//        System.out.println("main interrupted4: " + interrupted);      //false


    }


    /**
     * 自定义休眠方法
     *
     * @param timeOut
     */
    public static void sleep(long timeOut) {
        long start = timeOut + System.currentTimeMillis();
        long end;
        do {
            end = System.currentTimeMillis();
        } while (end <= start);
    }

public static Unsafe getUnSafe() {
            Field field = null;
            try {
                field = Unsafe.class.getDeclaredField("theUnsafe");
                field.setAccessible(true);
                return (Unsafe) field.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
}

最后的问题?

1.为什么要有中断状态?

当线程调用interrupt方法时,设置中断状态,可中断线程的sleep/wait/park状态,程序员可以获取中断状态进行业务逻辑操作。

2.线程的其他方法

这些问题将在后续文章中解答...感谢各位的阅读。

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 29
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值