java多线程之——停止线程多种方式

原文地址:

Java的中断机制使用一个中断变量作为标识,假如某个线程的中断变量被标记为true,那么这个线程在适当的时机会抛出异常,程序员捕获异常后进行相应的处理。要玩转线程中断,首先必须明白中断标识是如何检测和触发的。

中断标识方式🍊

针对“正在运行”的线程😎

java层自定义

package com.thread.threadSafe.stop;

/**
 * @program: thread
 * @author: xmonster_大魔王
 * @create: 2022-09-20 19:15
 * 在Java层自定义中断标识
 **/
public class InterruptThreadDemo extends Thread{
    private volatile boolean isInterrupted = false;
    public void customInterrupt(){
        isInterrupted = true;
    }

    @Override
    public void run() {

        while (!isInterrupted){
            System.out.println("我在跑!!");
        }
        System.out.println("我被打断啦!!");
    }

    public static void main(String[] args) {
        InterruptThreadDemo threadDemo = new InterruptThreadDemo();
        threadDemo.start();
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){

        }
        threadDemo.customInterrupt();
    }
}

 

 

使用JVM提供的中断标识

package com.thread.threadSafe.stop;

/**
 * @program: thread
 * @author: xmonster_大魔王
 * @create: 2022-09-20 19:15
 * 在Java层自定义中断标识
 **/
public class InterruptThreadDemo2 extends Thread{

    @Override
    public void run() {
        while (!Thread.interrupted()){
            System.out.println("我在跑!!");
        }
        System.out.println("我被打断啦!!");
    }

    public static void main(String[] args) {
        InterruptThreadDemo2 threadDemo = new InterruptThreadDemo2();
        threadDemo.start();
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){

        }
        threadDemo.interrupt();
    }
}

结果和上面一样

阻塞/等待状态中断方式🍉

对于可以运行的线程,我们需要通过while的形式来检测中断标识,而对于本身已经处于阻塞/等待状态的线程,则无需自己检测中断标识,我们要做的就是捕获中断异常并进行处理。😎
这里需要注意的就是:sleep会清除中断状态

睡眠

package com.thread.threadSafe.sleep.stop;

/**
 * @program: thread
 * @author: xmonster_大魔王
 * @create: 2022-09-19 22:08
 **/
public class MyThread extends Thread{

    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            Thread.sleep(2000);
            System.out.println("run end");
        }catch (InterruptedException e){
            System.out.println("在沉睡中被停止!进入了catch!!!!"+this.isInterrupted());
            e.printStackTrace();
        }
    }
    /**
     * run begin
     * main end!!
     * 在沉睡中被停止!进入了catch!!!!false
     * java.lang.InterruptedException: sleep interrupted
     *     at java.base/java.lang.Thread.sleep(Native Method)
     *     at com.thread.threadSafe.sleep.stop.MyThread.run(MyThread.java:15)
     *     如果线程在sleep方法中被打断,那么线程会进入catch语句,并且清除停止状态,变成false
     *     注意:这里是先sleep(),再interrupt()
     *     最终的结论:不管这两个方法谁先执行,只要是他们两个方法碰一起了,就必定会出现异常
     */
}

Run方法

package com.thread.threadSafe.sleep.stop;

/**
 * @program: thread
 * @author: xmonster_大魔王
 * @create: 2022-09-19 22:09
 **/
public class Run {
    public static void main(String[] args) throws InterruptedException {
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(200);
            myThread.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("main end!!");

    }
}

运行结果

 

其他的经典情景🍍

如果线程既可能处于可执行状态、又可能处于阻塞/中断状态,怎么处理?
这里其实就是对上面两个方法进行一个“综合”🥪
🥝既要有通过while循环来判断是否中断,在这个while循环中,线程还可能进入睡眠状态,睡眠状态是由JVM层面去支持中断的,所以当这个线程调用了中断方法之后,它会中断睡眠并抛出中断异常
🥑还记得上面说过的一个注意点吗,sleep捕获了异常之后它会清除中断标识,然后抛出异常,因为这个中断标识会被清除掉,所以我们要再次设置一下中断标识,不然上面的while循环跳不出来啦

package com.thread.threadSafe.stop;

/**
 * @program: thread
 * @author: xmonster_大魔王
 * @create: 2022-09-21 10:02
 **/
public class RunningWatingInterrupt {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("running...");
                try {
                    Thread.sleep(200);
                }catch (InterruptedException e){
                    System.out.println(Thread.currentThread().isInterrupted());
                    Thread.currentThread().interrupt();
                    System.out.println("thread has stoped!");
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(2000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        thread.interrupt();

    }
}

 

 

park的特殊中断

实际上通过park方式阻塞线程,它的终端方法比较特殊,这种阻塞方式下的中断不会抛出中断异常,但是中断标识会被设置成true,不会清除这个中断标识。

 

package com.thread.threadSafe.stop;

import java.util.concurrent.locks.LockSupport;

/**
 * @program: thread
 * @author: xmonster_大魔王
 * @create: 2022-09-21 10:30
 **/
public class park {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("i am running!!");
            LockSupport.park();  //关键点
        });
        thread.start();
        try {
            Thread.sleep(2000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        thread.interrupt();
        System.out.println(thread.isInterrupted());
    }
}

 

其它参考地址:

Java终止线程的三种方式

 

posted @ 2023-03-08 16:10  八方鱼  阅读(297)  评论(0)    收藏  举报