方法

解释

Thread.currentThread().interrupt();

给线程标记为中断状态

Thread.currentThread().isInterrupted();

返回线程中断标志位是否为中断,中断返回true,反之false

Thread.interrupted();

返回线程中断标志位是否为中断,中断返回true,反之false;并且清除之前的中断状态,即把当前线程改为非中断状态

Thread.currentThread().interrupt()

该方法为非静态方法,该方法的作用:标记线程为中断状态,仅仅是标记

/**
* @author chaird
* @create 2020-12-22 13:58
*/
public class Main {
public static void main(String[] args) {
// 获取当前线程
Thread currentThread = Thread.currentThread();
// 获取当前线程的中断状态
System.out.println(currentThread.isInterrupted()); // false
// 标记为中断线程
currentThread.interrupt();
// 获取当前线程的中断状态
System.out.println(currentThread.isInterrupted()); // true
}
}

Thread.currentThread().isInterrupted()

该方法为非静态方法,该方法的作用:返回线程的中断状态

/**
* @author chaird
* @create 2020-12-22 13:58
*/
public class Main {
public static void main(String[] args) {
// 获取当前线程
Thread currentThread = Thread.currentThread();
// 获取当前线程的中断状态
System.out.println(currentThread.isInterrupted()); // false
// 标记为中断线程
currentThread.interrupt();
// 获取当前线程的中断状态
System.out.println(currentThread.isInterrupted()); // false
}
}

Thread.interrupted()

/**
* @author chaird
* @create 2020-12-22 13:58
*/
public class Main {
public static void main(String[] args) {
// 获取当前线程
Thread currentThread = Thread.currentThread();
// 获取当前线程的中断状态
System.out.println(currentThread.isInterrupted()); // false
// 标记为中断线程
currentThread.interrupt();
// 获取当前线程的中断状态
System.out.println(currentThread.isInterrupted()); // false

// (1)获取当前线程的中断状态,(2)并且取消中断状态
boolean interrupted = Thread.interrupted();
System.out.println(interrupted); // true

System.out.println(currentThread.isInterrupted()); // false 。因为Thread.interrupted()中取消中断状态
}
}

如何正确的中断一个正在执行的线程

案例1:没有坑并且不带Sleep的代码

import java.time.LocalDateTime;

/**
* @author chaird
* @create 2020-12-22 14:15
*/
public class Start {
public static void main(String[] args) {

InterruptedTask interruptedTask = new InterruptedTask();
Thread interruptedThread = new Thread(interruptedTask);
interruptedThread.start();
try {
// 睡1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置线程为中断状态
interruptedThread.interrupt();
}
}

class InterruptedTask implements Runnable {

@Override
public void run() {

Thread currentThread = Thread.currentThread();
while (true) {
if (currentThread.isInterrupted()) {
break;
}
System.out.println("LocalDateTime:" + LocalDateTime.now().toString());
}
}
}

案例2:有坑并且带Sleep的代码

下述代码明明调用了线程的interrupt()方法来中断线程,但是却并没有起到啥作用。原因是线程的run()方法在执行的时候,大部分时间都是阻塞在sleep(100)上,当其他线程通过调用执行线程的interrupt()方法来中断执行线程时,大概率的会触发InterruptedException异常,在触发InterruptedException异常的同时,JVM会同时把线程的中断标志位清除,所以,这个时候在run()方法中判断的currentThread.isInterrupted()会返回false,也就不会退出当前while循环了。

import java.time.LocalDateTime;

/**
* @author chaird
* @create 2020-12-22 14:15
*/
public class Start {
public static void main(String[] args) {

InterruptedTask interruptedTask = new InterruptedTask();
Thread interruptedThread = new Thread(interruptedTask);
interruptedThread.start();
try {
// 睡1秒
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置线程为中断状态
interruptedThread.interrupt();
}
}

class InterruptedTask implements Runnable {

@Override
public void run() {
Thread currentThread = Thread.currentThread();
while (true) {
if (currentThread.isInterrupted()) {
break;
}
System.out.println("LocalDateTime:" + LocalDateTime.now().toString());
try {
// 睡0.1秒
Thread.sleep(100);
} catch (InterruptedException e) {

e.printStackTrace();
}
}
}
}

解决办法

import java.time.LocalDateTime;

/**
* @author chaird
* @create 2020-12-22 14:15
*/
public class Start {
public static void main(String[] args) {

InterruptedTask interruptedTask = new InterruptedTask();
Thread interruptedThread = new Thread(interruptedTask);
interruptedThread.start();
try {
// 睡1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置线程为中断状态
interruptedThread.interrupt();
}
}

class InterruptedTask implements Runnable {

@Override
public void run() {
Thread currentThread = Thread.currentThread();
while (true) {
if (currentThread.isInterrupted()) {
break;
}
System.out.println("LocalDateTime:" + LocalDateTime.now().toString());
try {
// 睡0.1秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
// 在触发InterruptedException异常的同时,JVM会同时把线程的中断标志位清除,所以需要复现中断状态
currentThread.interrupt();
}
}
}
}

案例3:有坑,需要JMM知识解决

主线程睡0.5秒,然后去中断interruptedThread线程,但是运行下面的代码线程并没有结束,说明有BUG

/**
* @author chaird
* @create 2020-12-22 14:15
*/
public class Start {
public static void main(String[] args) {

InterruptedTask interruptedTask = new InterruptedTask();
Thread interruptedThread = new Thread(interruptedTask);
interruptedThread.start();
try {
// 睡0.5秒
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
interruptedTask.myInterrupted();
}
}

class InterruptedTask implements Runnable {

private boolean sign = false;

@Override
public void run() {
Thread currentThread = Thread.currentThread();
while (!sign) {}
}

public void myInterrupted() {
sign = true;
}
}

解决办法

因为InterruptedTask里的while(true)太快了,没有任何逻辑,所以一个字:快。

虽然JMM中主内存中的更新了数据,但是本地内存来不及去主内存中更新数据,所以上面的案例中InterruptedTask里的sign一直都是false。volatile可以解决内存可见性。这就是另一个知识点了,不多解释。


private boolean sign = false
改为
private volatile boolean sign = false;

注意

本文中说的中断状态其实就是一个标志位,而不是真正的中断线程

class MyThread {
// 中断状态标志位
private volatile boolean sign = false;
}

参考

​我们该如何正确的中断一个正在执行的线程??​

​JVM笔记_CBeann的博客-​