1. 前言
今天的主题是:
如何优雅的中断线程
。 会列举出几种中断线程的办法,同时也会扩展一定的知识。废话不多说,我们开始吧!!!
2. 前置知识
2.1 interrupt
API
此API号称是可以中断线程。但是其实这种想法有一定的歧义。不应该说是可以中断线程,而是对线程进行标记。通过判断标记来中断线程
2.1.1 基本的API
public void interrupt
此方法是一个实例方法,用来标记线程public boolean isInterrupted
此方法是一个实例方法,用来判断线程是否被标记public static boolean interrupted
此方法是一个静态方法,返回判断是否被标记,同时清空标记
2.1.2 实例
public class Thread_04_interrupt_study {
public static void main(String[] args) throws InterruptedException {
testInterrupt02();
}
public static void testInterrupt02() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (;;) {
if (Thread.interrupted()) {
System.out.println("此线程被标记了,并且清除了标记");
break;
}
System.out.println("这是一个子线程:" + Thread.currentThread().getName());
}
});
t1.start();
Thread.sleep(1000);
t1.interrupt();
Thread.sleep(1000);
System.out.println("是否还有状态:" + t1.isInterrupted());
}
public static void testInterrupt01() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (;;) {
// 判断线程是否被标记中断
if (Thread.currentThread().isInterrupted()) {
System.out.println("此进程被标记了");
break;
}
System.out.println("这是一个子进程:" + Thread.currentThread().getName());
}
});
t1.start();
Thread.sleep(1000);
// 此时对线程进行标记
t1.interrupt();
}
}
2.2 当interrupt
遇到join
/ sleep
/ wait
时
- 当
interrupt
遇到sleep/ wait
等得时候,程序会报错。所以我们可以捕获异常,在异常中做别的处理- 换言之,当
interrupt
遇到sleep
等 会打断原来要做的事情。 开始执行异常
public class Thread_05_interrupt_sleep_wait {
public static final Object o = new Object();
public static void main(String[] args) throws InterruptedException {
test02();
}
public static void test02() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
synchronized (o) {
try {
o.wait();
} catch (InterruptedException e) {
System.out.println("遇到异常了 重新执行");
}
}
}
});
t1.start();
Thread.sleep(1000);
t1.interrupt();
}
public static void test01() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("sleep 被唤醒可以继续执行了");
}
if (Thread.interrupted()) {
System.out.println("我是被标记的线程:" + Thread
.currentThread().getName());
}
}
});
t1.start();
Thread.sleep(1000);
t1.interrupt();
}
}
2.3 当interrupt
遇到synchronized/ lock
时
结论:
interrupt
不会中断竞争锁的线程。 但是lockInterruptibly
除外
public class Thread_06_interrupt_sync {
private static final Object o = new Object();
public static void main(String[] args) throws InterruptedException {
test01();
}
public static void test01() throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (o) {
try {
System.out.println("wo shi t1");
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
Thread.sleep(1000);
Thread t2 = new Thread(() -> {
synchronized (o) {
}
System.out.println("wo shi t2");
});
t2.start();
Thread.sleep(1000);
t2.interrupt();
}
}
3. 中断线程的几种方式
3.1 stop
我们可以使用API【stop】进行中断。但是此API已经被废弃了。同样是不推荐使用。因为过于粗暴,无法保证数据的一致性。
public static void testStop01() throws InterruptedException {
Thread t1 = new Thread(() -> {
while (true) {
try {
Thread.sleep(1000);
System.out.println("这是一个线程" + Thread.currentThread().getName());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
Thread.sleep(2000);
t1.stop();
}
3.2 suspend/ resume
通过暂停以及启动 可以中断线程。但是也是因为粗暴,而且无法准备的判断。所以其实不支持使用它来中断线程的
public static void testStop02() throws InterruptedException {
Thread t1 = new Thread(() -> {
while (true) {
System.out.println("这是一个线程:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
Thread.sleep(2000);
// 表示暂停
t1.suspend();
Thread.sleep(2000);
// 表示开始
t1.resume();
}
3.3 volatile
可以通过
volatile
轻量锁来实现线程中断。其实就是一个特殊的flag。 控制起来相对比较灵活,值得推荐
public static void testStop03() throws InterruptedException {
Thread t1 = new Thread(() -> {
Integer count = 0;
while (running) {
if (count >= 10) {
running = false;
}
try {
Thread.sleep(100);
count ++;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("同步 执行结束");
});
t1.start();
Thread.sleep(2000);
}
3.4 interrupt
我们可以通过API【interrupt】进行线程标记。通过判断线程是否被标记来执行别的逻辑。这种方式相对来说会更加优雅一点。 但是其实上述方式
3.3
也相对比较优雅
public static void testStop04() throws InterruptedException {
Thread t1 = new Thread(() -> {
while (!Thread.interrupted()) {
}
System.out.println(
"执行当前线程" + Thread.currentThread().getName()
);
});
t1.start();
Thread.sleep(2000);
t1.interrupt();
}
4. 总结
上述是几种中断线程的方式。不管是理由还是代码都列举出来了。源码参照这个地方. 如果大家有不同的意见,欢迎评论区留言。让我们一起成长。