鉴于最近找实习并发编程问的挺多的,闲暇之际特来整理一下:
首先
一个线程不应该由其他线程来强制中断或停止,而是 应该由线程自己自行停止,自己来决定自己的命运。
所以,Thread.stop,Thread.suspend,Thread.resume 都已经废弃了。
其次
在 Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。
因此,Java提供了一种用于停止线程的协商机制——中断,即中断标识协商机制。
中断只是一种协作协商机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。
若要中断一个线程,你需要手动调用该线程的 interrupt方法,该方法也仅仅是将线程对象的中断标识设成 true。
接着你需要自己写代码不断地检测当前线程的标识位,如果为 true,表示别的线程请求这条线程中断,此时究竟做什么需要你自己写代码实现。
每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该表示位为true表示中断,为false表示未中断;通过调用线程对象的 interrupt方法将线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。
即:中断只是一种协商机制,修改中断标识位仅此而已,不是立刻stop打断。
一、实现中断运行中的线程
比如说老师总会问 如何停止中断运行中的线程?那么这里小伟为大家整理主要有以下三种方式:
通过volatile实现线程中断停止
private static void m1_volatile() {
new Thread(()->{
while (true) {
if (isStop) {
System.out.println(Thread.currentThread().getName()+"\t isStop 被修改为true,程序停止");
break;
}
System.out.println("t1 -----hello volatile");
}
},"t1").start();
// 暂停20毫秒
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
isStop = true;
},"t2").start();
}
通过 AtomicBoolean实现线程中断停止
AtomicBoolean(原子布尔型)
private static void m2_atomicBoolean() {
new Thread(()->{
while (true) {
if (atomicBoolean.get()) {
System.out.println(Thread.currentThread().getName()+"\t atomicBoolean 被修改为true,程序停止");
break;
}
System.out.println("t1 -----hello atomicBoolean");
}
},"t1").start();
// 暂停20毫秒
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
atomicBoolean.set(true);
},"t2").start();
}
通过Thread类自带的中断Api实例方法实现
在需要中断的线程中 不断监听中断状态,一旦发生中断,就执行相应的中断处理业务逻辑stop线程
private static void m3_ThreadApi() {
Thread t1 = new Thread(()->{
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + "\t isInterrupted()被修改为true,程序停止");
break;
}
System.out.println("t1 ----hello interrupt api");
}
},"t1");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
t1.interrupt();
},"t2").start();
}
二、中断的相关API方法
接下来我们对 Thread类自带的中断Api实例方法进行探索吧~
再次来探讨一下如何停止线程吧?
- run 方法执行完成,自然终止;
- stop() 方法、suspend()、resume() 都是过期作废方法,使用它们结果不可预期;
大多数停止一个线程的操作使用 Thread.interrupted() 等于说给线程打一个停止的标记,此方法不会去终止一个正在运行的线程,需要加入一个判断才能可以完成线程的终止;
- interrupted :判断当前线程是否已经中断,会清除状态;
- isInterrupted :判断线程是否已经中断,不会清除状态;
通过Api文档对以上三个方法做个简单的介绍吧:
-
public void interrupt() :中断这个线程
源码注解:Just to set the interrupt flag
实例方法 interrupt() 仅仅是设置线程的中断状态为 true,发起一个协商而不会立刻停止线程。
-
public static boolean interrupted() :判断当前线程是否已经中断,会清除状态;
这个方法做了两件事:
- 返回当前线程的中断状态,测试当前线程是否已被中断
- 将当前线程的中断状态清零并重新设为false,清除线程的中断状态
-
public boolean isInterrupted():判断当前线程是否被中断(通过检查中断标志位)
源码探究时刻~
让我们来看看interrupt()
方法的源码,发现实则是调用了本地方法 interrupt0()
,Just to set the interrupt flag,仅是将该线程的中断标志设置为true。所以,interrupt()
方法并不能真正的中断线程,需要被调用的线程自己进行配合才行。
当然,如果线程处于被阻塞状态(例如处于 sleep、wait、join 等状态),在别的线程中调用当前线程对象 interrupt()
方法,那么线程将立即退出被阻塞状态,并清除它的中断状态,并抛出一个 InterruptedException异常。此时线程的中断标志位为false,中断不打断。解决方法是:在catch()代码块中调用 interrupt()
方法。
再来看看 interrupted()
、 isInterrupted()
方法的源码,发现两个方法底层都是调用了本地方法isInterrupted()
,该方法注解内容为:测试某个线程是否中断。中断状态是否重置取决于传递的ClearInterrupted的值。
- interrupted() ——> isInterrupted(true):判断当前线程是否已经中断,会清除状态;
- isInterrupted ——> isInterrupted(false) :判断线程是否已经中断,不会清除状态;
今儿就先到这里啦,小伟查缺补漏去咯~