1.中断协商机制
线程不应该由其他线程来强制中断或暂停,应该由线程自己自行停止。这意味着Thead.stop,Thead.suspend,Thead.resume都已经被废弃。
在Java中没有办法立即停止一条线程,然而停止线程尤为重要,例如取消一个耗时的操作。
因此,Java提供一种用于停止线程的协商机制(中断),中断标识协商机制。
中断是一种协商机制,Java没有给中断添加任何语法,中断的过程完全由程序员自己实现。
如果想中断一个线程,可以手动调用interrupt方法,该方法也仅仅将线程对象的中断标识设置为true,接着你需要写代码不断检查当前线程的标识位,如果为true,则表示别的线程请求该线程中断。
每个线程对象都有一个中断标识位,用于表示线程是否被中断,该标识位为true表示中断,标识位为false表示未中断;通过调用线程对象的interrupt方法将线程标识位设置为true。既可以在别的线程中调用,也可以在自己的线程中调用。
2. 中断3大方法
interrupt()
:当调用某个线程的interrupt()
方法时,该线程的中断状态将被设置为true
。如果该线程当前被Object.wait()
,Thread.join()
或Thread.sleep()
方法阻塞,那么线程的中断状态将被清除,并且线程将接收到一个InterruptedException
。如果该线程在运行中且没有阻塞在这些方法上,那么中断状态将被设置,但线程将继续运行,除非它定期检查中断状态。interrupted()
:用于检查当前线程是否已被中断,并清除当前线程的中断状态。如果当前线程的中断状态被设置,则返回true
,并且在返回前清除中断状态。- isInterrupted():它用于检查调用此方法的线程是否已被中断。如果线程的中断状态被设置,则返回
true
,否则返回false
。此方法不会清除线程的中断状态。
3. 通过volatile实现线程中断停止
public class VolatileInterruptExample {
// 使用volatile关键字确保可见性
private static volatile boolean running = true;
public static void main(String[] args) throws InterruptedException {
Thread workerThread = new Thread(() -> {
while (running) {
// 执行任务...
System.out.println("线程正在运行...");
// 为了演示,我们在这里加入一个简单的延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 当线程被中断时,通常会抛出InterruptedException
// 在这里我们可以选择退出循环,也可以选择其他逻辑
System.out.println("线程被中断,退出循环");
break;
}
}
System.out.println("线程已停止");
});
// 启动线程
workerThread.start();
// 主线程暂停一段时间,然后设置running为false来停止工作线程
Thread.sleep(3500);
running = false;
// 等待工作线程结束
workerThread.join();
System.out.println("主线程结束");
}
}
- 我们定义了一个
volatile
布尔变量running
,它用来控制工作线程的执行。 - 工作线程在它的
run
方法中运行一个循环,循环的条件是running
为true
。 - 在主线程中,我们让工作线程运行一段时间后,通过将
running
设置为false
来停止工作线程。 - 工作线程在检测到
running
变为false
后,会退出循环并结束运行。
volatile
关键字确保了running
变量的改变对所有线程立即可见,这是实现线程安全的一个重要特性。当主线程修改running
的值时,工作线程能够立即看到这个变化,从而正确地响应停止信号。
4. 通过AutomicBoolean实现线程中断停止
AtomicBoolean
提供了原子操作布尔值的方法。使用 AtomicBoolean
可以安全地在多个线程之间共享一个布尔值
import java.util.concurrent.atomic.AtomicBoolean;
public class AtomicBooleanInterruptExample {
// 使用AtomicBoolean来确保线程安全
private static AtomicBoolean running = new AtomicBoolean(true);
public static void main(String[] args) throws InterruptedException {
Thread workerThread = new Thread(() -> {
while (running.get()) {
// 执行任务...
System.out.println("线程正在运行...");
// 为了演示,我们在这里加入一个简单的延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 当线程被中断时,通常会抛出InterruptedException
System.out.println("线程被中断,退出循环");
break;
}
}
System.out.println("线程已停止");
});
// 启动线程
workerThread.start();
// 主线程暂停一段时间,然后设置running为false来停止工作线程
Thread.sleep(3500);
running.set(false);
// 等待工作线程结束
workerThread.join();
System.out.println("主线程结束");
}
}
- 我们创建了一个
AtomicBoolean
类型的running
变量,并初始化为true
。 - 工作线程在它的
run
方法中运行一个循环,循环的条件是running.get()
返回true
。 - 在主线程中,我们让工作线程运行一段时间后,通过调用
running.set(false)
来停止工作线程。 - 工作线程在检测到
running
变为false
后,会退出循环并结束运行。
AtomicBoolean
的 get
和 set
方法保证了操作的原子性,这意味着在多线程环境中,这些操作不会被其他线程中断,从而保证了线程安全。这是 AtomicBoolean
优于普通布尔变量的一个重要方面。使用 AtomicBoolean
,我们不需要担心可见性和原子性问题,因为它内部已经处理了这些问题。
5. 通过interrupt实现线程中断
在需要中断单点线程中不断监听中断状态,一旦发生中断,就执行相应中断处理业务逻辑停止线程。
public class InterruptExample {
public static void main(String[] args) throws InterruptedException {
// 创建一个线程
Thread workerThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 执行任务...
System.out.println("线程正在运行...");
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 在这里捕获InterruptedException异常
// 这通常是我们想要中断线程的地方
System.out.println("线程在sleep期间被中断");
// 由于中断状态被清除,我们需要重新设置中断状态
Thread.currentThread().interrupt();
// 选择退出循环或者进行其他清理工作
break;
}
}
System.out.println("线程已停止");
});
// 启动线程
workerThread.start();
// 主线程暂停一段时间,然后中断工作线程
Thread.sleep(3500);
workerThread.interrupt();
// 等待工作线程结束
workerThread.join();
System.out.println("主线程结束");
}
}
- 我们创建了一个工作线程,它在一个循环中执行任务,并在每次迭代后调用
Thread.sleep(1000)
来模拟耗时操作。 - 循环的条件是
!Thread.currentThread().isInterrupted()
,这意味着如果线程的中断状态被设置,循环将终止。 - 当工作线程在
sleep
期间被中断时,会抛出InterruptedException
。在catch
块中,我们捕获了这个异常。 - 在捕获
InterruptedException
后,我们通过调用Thread.currentThread().interrupt()
重新设置了线程的中断状态,因为在抛出InterruptedException
后,中断状态会被清除。 - 我们选择退出循环,这样线程就可以执行任何必要的清理操作,然后退出。
6. 中断协商深度解析
(1)调用 interrupt() 时,如果线程处于正常活动状态,会将线程的中断标识设置为true,被设置中断标识的线程将继续正常运行,不受影响。
(2)中断不活动的线程不会产生任何影响,使用interrupt后,isInterrupted的结果为false
(3)线程处于阻塞状态,在别的线程中调用当前线程的interrupt方法,那么线程将立即退出被阻塞的状态,并抛出一个InterruptedException异常。