0
点赞
收藏
分享

微信扫一扫

多线程学习二,线程生命周期和线程中断

大师的学徒 2022-01-21 阅读 144

多线程学习二,线程生命周期和线程中断

1. Java线程生命周期

思维导图:

image-20220121111254673

示意图:

image-20220121111226777

2. 线程中断

思维导图:

image-20220121111534892

在java的世界里,Thread类是对线程概念的抽象。想要中断一个线程有两种方式:

  • (1)调用Thread类的stop方法
  • (2)组合调用Thread类的interruptinterruptedisInterrupted方法

​ 通过源码的注释我们可以知道,调用stop()可能会产生线程异常,抛出SecurityException异常。其原因为使用stop方法进行中断线程本质上是不安全的,它会直接释放掉本线程所持有的所有资源,举个简单的栗子来说,假如我们正在使用某个线程下载电影,如果该线程或者其他线程通过该线程的stop进行中断,则原来下载的内容将全部丢失。

由此我们可以知道Java线程的设计是协作式的,而不是抢占式的,

image-20220121111922631

2.1 interrupt()实现中断

interrupted()方法是发起线程中断请求,但只是请求,并不会真的把线程给中断,实际上是把线程的中断标识设置为了true

public static void main(String[] args) {
    //通过interrupted() 方法检测线程是否被中断
    System.out.println(Thread.currentThread().getName()+"线程是否中断"+Thread.interrupted());
    //设置线程中断
    Thread.currentThread().interrupt();
    //通过interrupted()方法检测线程是否被中断,并且会恢复中断
    System.out.println(Thread.currentThread().getName()+"线程是否中断"+Thread.interrupted());
}

输出:
    main线程是否中断false
    main线程是否中断true

2.2 isInterrupted()检查线程中断

isInterrupted()方法是判断线程的中断标识是否为true

public static void main(String[] args) {
    //当前线程
    Thread thread = Thread.currentThread();
    //检测当前线程时候被中断
    System.out.println(thread.getName()+"线程是否中断"+thread.isInterrupted());
    //设置当前线程的中断标识
    thread.interrupt();
    //检测当前线程是否中断
    System.out.println(thread.getName()+"线程是否中断"+thread.isInterrupted());
    //检测当前线程中断状态是否被清除
    System.out.println(thread.getName()+"线程是否中断"+thread.isInterrupted());
    try {
        //线程休眠2s
        //这里设置的是线程休眠20s,但是因为线程中断,所有sleep会被打断
        Thread.sleep(20000);
        System.out.println(thread.getName()+"线程休眠未被中断...");
    } catch (Exception e) {
        System.out.println(thread.getName()+"线程休眠被中断...");
        //判断线程是都被中断
        System.out.println(thread.getName()+"线程是否中断"+thread.isInterrupted());
    }finally {
        System.out.println(thread.getName()+"线程是否中断"+thread.isInterrupted());
    }
}

输出结果:
    main线程是否中断false
    main线程是否中断true
    main线程是否中断true
    main线程休眠被中断...sleep interrupted
    main线程是否中断false
    main线程是否中断false

​ 在这个栗子中我们看到线程在设置interrupt()后,会继续往下执行,并没有马上中断,这其实只是发起线程中断请求,并不会真的把线程给中断,只是把线程的中断标识设置为了true。CPU在执行线程时又没有阻塞也没有转到其他语句,当然要往下执行,interrupt()只是抛出一个消息,“要求”调用他的进程中断,他只是负责发出要求,具体执行由其他函数实现。所以这个语句出现进程不会中断。

​ 🚩在线程执行到Thread.sleep(20000)时,线程由运行态转换为阻塞态,但是因为设置了线程中断,所以sleep()会执行终端,线程会退出阻塞态继续执行,由此可以我们可以知道interrupt()是中断处于阻塞/睡眠状态的线程,需要注意的是这里的中断并不是让线程死亡, 而是退出阻塞状态继续运行,所以interrupt不能中断运行中的线程。

jdk里interrupt()解释:

image-20220121120938507

当然 Java 也有很多底层实现是看不到的:

image-20220121122201266

2.3 interrupted检测线程中断并清除中断

没有栗子,可以看2.1的栗子

2.4 线程中断异常处理

在2.2中我们可以知道,当线程阻塞的调用一些方法会导致InterruptedException异常抛出

在捕获异常的时候我们也可以对其进行异常处理

  • 抛出 InterruptedException
  • 捕获InterruptedException后重新抛出。
  • 检测到中断后,重新设置线程中断.
//捕获InterruptedException后重新抛出。
public static void main(String[] args) throws InterruptedException {
    //当前线程
    Thread thread = Thread.currentThread();
    try {
        //设置当前线程的中断标识
        thread.interrupt();
        Thread.sleep(20000);
    } catch (InterruptedException e) {
        System.out.println(thread.getName()+"线程休眠被中断..."+e.getMessage());
        //判断线程是都被中断
        System.out.println(thread.getName()+"执行终端处理");
        throw e;
    }
输出:
    main线程休眠被中断...sleep interrupted
    main执行终端处理
    Exception in thread "main" java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at com.fx.multiThread._7_HandleInterruptedException.main(_7_HandleInterruptedException.java:15)
//检测到中断后,重新设置线程中断. 
public class _8_ReInterrupted extends Thread{
    public static void main(String[] args) throws InterruptedException {
        //当前线程main
        String threadName = Thread.currentThread().getName();
        _8_ReInterrupted reInterrupted = new _8_ReInterrupted();
        System.out.println(printDate() + threadName + " 线程启动");
        //启动新线程
        reInterrupted.start();
        //主线程休眠3秒
        Thread.sleep(3000);
        System.out.println(printDate() + threadName + " 设置子线程中断");
        //对子线程设置线程中断  在主线程里面操作其他线程
        reInterrupted.interrupt();
        //主线程休眠3秒
        Thread.sleep(3000);
        System.out.println(printDate() + threadName + " 运行结束");
    }

    @Override
    public void run() {
        //当前线程
        String threadName = Thread.currentThread().getName();
        int i = 0;
        //循环等待线程中断
        while (!Thread.currentThread().isInterrupted()){//只判断状态不清除状态
            System.out.println(printDate() + threadName + " 线程正在执行第:"+(++i)+"次");
            try {
            	//线程阻塞,如果线程收到中断操作型号将抛出异常
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println(printDate() + threadName + " 线程抛出异常");
                //检测线程是否中断
                System.out.println(printDate() + threadName + " 线程是否被中断" + this.isInterrupted());
                //TODO 如果不需要则不用调用  如果调用Interrupt()方法的话,则当前线程状态变为中断,将退出循环,程序结束
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(printDate() + threadName + " 线程是否被中断" + this.isInterrupted());
        System.out.println(printDate() + threadName + " 线程退出");
    }
    //打印当前事件
    private static String printDate() {
        return new SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())+"\t";
    }
}










举报

相关推荐

0 条评论