在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 标志位;
当对一个线程调用了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));
}
}
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博客