Java一个线程结束另一个线程,Java如何停止一个线程?

在Java中停止一个线程有三种办法 :
1.正常结束执行;
2.发生异常;
3.被其他线程stop(Java官方不建议)
参考:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

一个线程A会一直执行下去停不下来,外部线程B不可以直接主动停止线程A,但是线程B可以发送停止信号给A,A通过这个信号判断是否结束线程。

如果A线程没有这种信号量那么B线程还可以主动停止他么?答案是不可以!

虽然线程不能在中间被停止/干掉,但是任务是可以停止的;
想让线程结束的目的是让任务结束,而不是强制线程结束。
有两种方式结束任务,分别是:Interrupt 和使用 volatile boolean 标志位;

1、interrupt

当对一个线程调用了interrupt()之后,如果该线程处于被阻塞状态(比如执行了wait、sleep或join等方法),那么会立即退出阻塞状态,并抛出一个InterruptedException异常。

也就是对线程A执行interrupt()方法后,线程A内部的sleep方法会抛出InterruptedException异常,我们可以根据这个信号,结束线程A。

public class Test {
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("--- 子线程1 " + LocalDateTime.now().format(formatter));
                    } catch (InterruptedException e) {
                        System.out.println("--- 子线程3 " + LocalDateTime.now().format(formatter));
                        break;
                    }
                    System.out.println("--- 子线程2 " + LocalDateTime.now().format(formatter));
                }
                System.out.println("--- 子线程4 " + LocalDateTime.now().format(formatter));
            }
        });
        thread.start();
        System.out.println("=== 主线程1 " + LocalDateTime.now().format(formatter));
        Thread.sleep(2100);
        System.out.println("=== 主线程2 " + LocalDateTime.now().format(formatter));
        thread.interrupt();
        System.out.println("=== 主线程3 " + LocalDateTime.now().format(formatter));
    }
}

执行结果:
=== 主线程1 2024-02-18 21:04:03
--- 子线程1 2024-02-18 21:04:04
--- 子线程2 2024-02-18 21:04:04
--- 子线程1 2024-02-18 21:04:05
--- 子线程2 2024-02-18 21:04:05
=== 主线程2 2024-02-18 21:04:05
=== 主线程3 2024-02-18 21:04:05
--- 子线程3 2024-02-18 21:04:05
--- 子线程4 2024-02-18 21:04:05

 对线程A执行interrupt()方法后,线程A的Thread.currentThread().isInterrupted()结果为true,我们可以根据这个信号,结束线程A。

public class Test {
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("--- 子线程1 " + LocalDateTime.now().format(formatter));
                }
                System.out.println("--- 子线程4 " + LocalDateTime.now().format(formatter));
            }
        });
        thread.start();
        System.out.println("=== 主线程1 " + LocalDateTime.now().format(formatter));
        Thread.sleep(1);
        System.out.println("=== 主线程2 " + LocalDateTime.now().format(formatter));
        thread.interrupt();
        System.out.println("=== 主线程3 " + LocalDateTime.now().format(formatter));
    }
}

 需要注意:sleep抛出异常时会将Thread.currentThread().isInterrupted()重新置为false,下面的代码线程A永远不会结束。

public class Test {
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("--- 子线程1 " + LocalDateTime.now().format(formatter));
                    } catch (InterruptedException e) {
                        System.out.println("--- 子线程3 " + LocalDateTime.now().format(formatter));
                        // 不处理sleep抛出的异常,但是会将Thread.currentThread().isInterrupted()重新置为false
                        // break;
                    }
                    System.out.println("--- 子线程2 " + LocalDateTime.now().format(formatter));
                }
                System.out.println("--- 子线程4 " + LocalDateTime.now().format(formatter));
            }
        });
        thread.start();
        System.out.println("=== 主线程1 " + LocalDateTime.now().format(formatter));
        Thread.sleep(2100);
        System.out.println("=== 主线程2 " + LocalDateTime.now().format(formatter));
        thread.interrupt();
        System.out.println("=== 主线程3 " + LocalDateTime.now().format(formatter));
    }
}

将两种方式的信号结合起来如下:


public class Test {
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("--- 子线程1 " + LocalDateTime.now().format(formatter));
                    } catch (InterruptedException e) {
                        System.out.println("--- 子线程3 " + LocalDateTime.now().format(formatter));
                        // 不处理sleep抛出的异常,但是会将Thread.currentThread().isInterrupted()重新置为false
                        break;
                    }
                    System.out.println("--- 子线程2 " + LocalDateTime.now().format(formatter));
                }
                System.out.println("--- 子线程4 " + LocalDateTime.now().format(formatter));
            }
        });
        thread.start();
        System.out.println("=== 主线程1 " + LocalDateTime.now().format(formatter));
        Thread.sleep(2100);
        System.out.println("=== 主线程2 " + LocalDateTime.now().format(formatter));
        thread.interrupt();
        System.out.println("=== 主线程3 " + LocalDateTime.now().format(formatter));
    }
}

2、用volatile boolean标志位


public class Test {
    // 为了保证内存可见性,给boolean标志位添加volatile保证可见性
    private static volatile boolean stop = false;
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!stop) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("--- 子线程1 " + LocalDateTime.now().format(formatter));
                    } catch (InterruptedException e) {
                        System.out.println("--- 子线程3 " + LocalDateTime.now().format(formatter));
                        // break;
                    }
                    System.out.println("--- 子线程2 " + LocalDateTime.now().format(formatter));
                }
                System.out.println("--- 子线程4 " + LocalDateTime.now().format(formatter));
            }
        });
        thread.start();
        System.out.println("=== 主线程1 " + LocalDateTime.now().format(formatter));
        Thread.sleep(2100);
        System.out.println("=== 主线程2 " + LocalDateTime.now().format(formatter));
        // thread.interrupt();
        stop = true;
        System.out.println("=== 主线程3 " + LocalDateTime.now().format(formatter));
    }
}

执行结果:
=== 主线程1 2024-02-18 21:29:41
--- 子线程1 2024-02-18 21:29:42
--- 子线程2 2024-02-18 21:29:42
--- 子线程1 2024-02-18 21:29:43
--- 子线程2 2024-02-18 21:29:43
=== 主线程2 2024-02-18 21:29:43
=== 主线程3 2024-02-18 21:29:43
--- 子线程1 2024-02-18 21:29:44
--- 子线程2 2024-02-18 21:29:44
--- 子线程4 2024-02-18 21:29:44

使用interrupt()方式更优。

参考:

Java一个线程能否结束另一个永不停止的线程_java 线程1结束线程2-CSDN博客

你可能感兴趣的:(java,java,开发语言)