Thread.start和interrupt方法源码分析

一、start方法

对于线程的Thread类有个核心的方法叫做start(),其底层调用了start0()这个native方法。
在这里插入图片描述
想要继续深入了解start0干了什么事情,我们就需要下载一个OpenJDK
openjdk中写JNI一般是一一对应的,Thread.java对应的就是Thread.c(位于openjdk8\jdk\src\share\native\java\lang目录下),此时查看源码可以看到在jvm.h中找到了声明

在这里插入图片描述
继续读jvm.cpp文件(openjdk8\hotspot\src\share\vm\prims)中的JVM_StartThread方法
在这里插入图片描述
在这里插入图片描述
通过阅读上面的方法,我们看到了关键性的调用Thread::start(native_thread),所以我们需要继续往下追,看thread.cpp文件(位于openjdk\hotspot\src\share\vm\runtime目录下),经过分析源码包括注释内容,我们发现其实最底层是由操作系统来分配线程。
在这里插入图片描述

二、interrupt方法

什么是中断机制?

1.一个线程不应该由其他线程来强制中断或停止,而是应该山线程自己自行停止,自己来决定自己的命运。所以,Thread.stop,Thread.suspend, Thread.resume都已经被废弃了。在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的协商机制―—中断,也即中断标识协商机制。
2.若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程请求这条线程中断。
3.每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。

Thread类中的三个Interrupt方法:
在这里插入图片描述

1.源码分析

interrupt分析:
①如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。所以,interrupt()并不能真正的中断线程,需要被调用的线程自己进行配合才行。
②如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。

在这里插入图片描述
isInterrupted:
在这里插入图片描述
interrupted:
在这里插入图片描述
可以发现上面两个方法的本质是一样的!clearInterrupted为true就会清理线程的中断标志位!

2.如何停止中断运行中的线程?

以下列举了三种方法!

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class InterruptTest {

    static volatile boolean bool = false;
    static AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    public static void m1() throws InterruptedException {
        new Thread(()->{
            while (true) {
                if (bool){
                    System.out.println("interrupt.....");
                    break;
                }
                System.out.println("哦嗷嗷嗷");
            }
        },"A").start();
        TimeUnit.MICROSECONDS.sleep(20);
        new Thread(()->{
            bool = true;
        },"B").start();
    }
    
    public static void m2() throws Exception{
        new Thread(()->{
            while (true) {
                if (atomicBoolean.get()){
                    System.out.println("interrupt.....");
                    break;
                }
                System.out.println("哦嗷嗷嗷");
            }
        },"A").start();
        TimeUnit.MICROSECONDS.sleep(20);
        new Thread(()->{
            atomicBoolean.set(true);
        },"B").start();
    }
    
    public static void m3() throws Exception{
        Thread a = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("interrupt.....");
                    break;
                }
                System.out.println("aaaaaa");
            }
        }, "A");
        a.start();

        TimeUnit.MICROSECONDS.sleep(20);
        new Thread(()->{
            a.interrupt();
        },"B").start();
    }

    public static void main(String[] args) throws Exception {
//        m1();
//        m2();
        m3();
    }
}

3.当前线程中断标识为true,是不是线程就立即停止?

不是!!!证明如下

public class ThreadFlag {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 1; i <= 300; i++) System.out.println("---:" + i);
        }, "t1");
        t1.start();
        System.out.println("t1线程默认的中断标识:"+t1.isInterrupted());
        try { TimeUnit.MILLISECONDS.sleep(2);}catch (InterruptedException e) {e.printStackTrace();}
        t1.interrupt();//设置标识为true
        System.out.println("t1线程调研员interrupt后的中断标识为"+t1.isInterrupted() );
        //以下结果为false!!!!!!!!!!!!!!
		try { TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("由于打印完毕,变成了不活跃的线程:"+t1.isInterrupted() );
    }
}

在这里插入图片描述

4.InterruptException报错的解决

如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。

以下代码如果不在t1线程中加上 Thread.currentThread().interrupt();这一行,程序就会一直打印hello永不停止!

public class Example {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                if(Thread.currentThread().isInterrupted()){
                    System.out.println("中断标识为true,程序停止!!!!");
                    break;
                }
                try {
                    Thread.sleep(20);
                }catch (InterruptedException e) {
                    Thread.currentThread().interrupt();//不加这一行程序就会一直运行
                    e.printStackTrace();
                }
                System.out.println("hello");
            }
        },"t1");
        t1.start();

        try { TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e) {e.printStackTrace();}
        new Thread(()->{ t1.interrupt(); },"t2").start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

键盘歌唱家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值