JUC之线程中断机制解读(interrupt)

简介: JUC之线程中断机制解读(interrupt)

首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,自己来决定自己的命运。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。

其次,在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的协商机制―—中断,也即中断标识协商机制。

可以通过一个标志位来进行线程的中断

1. public class interruptDemo {
2. static volatile boolean isStop = false;
3. 
4. public static void main(String[] args) {
5. new Thread(() -> {
6. while (true) {
7. if (isStop) {
8.                     System.out.println(Thread.currentThread().getName() + "\t isStop被修改为true,程序停止");
9. break;
10.                 }
11.                 System.out.println("t1 is come in ...");
12.             }
13. 
14.         }, "t1").start();
15. try { TimeUnit.MICROSECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
16. new Thread(() -> {
17.             isStop = true;
18.         }, "t2").start();
19. 
20. 
21.     }
22. }

中断只是一种协作协商机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程请求这条线程中断,此时究竟该做什么需要你自己写代码实现。

每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。

1. Thread t1 = new Thread(() -> {
2. while (true) {
3. if (Thread.currentThread().isInterrupted()) {
4.                     System.out.println(Thread.currentThread().getName() + "\t isStop被修改为true,程序停止");
5. break;
6.                 }
7.                 System.out.println("t1 is come in ...");
8.             }
9. 
10.         }, "t1");
11.         t1.start();
12. try { TimeUnit.MICROSECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
13.         t1.interrupt();
14.     }

isInterrupted()

1. public boolean isInterrupted() {
2. return isInterrupted(false);
3.     }

测试此线程是否已中断。线程的 中断状态 不受此方法的影响。
由于线程在中断时未处于活动状态而被忽略的线程中断将由此方法反映,返回 false。

isInterrupted(boolean ClearInterrupted)

1. public static boolean interrupted() {
2. return currentThread().isInterrupted(true);
3.     }

测试当前线程是否已中断。此方法将清除线程的 中断状态 。换句话说,如果要连续调用此方法两次,则第二次调用将返回 false(除非在第一个调用清除其中断状态之后,在第二个调用检查它之前,当前线程再次中断)。
由于线程在中断时未处于活动状态而被忽略的线程中断将由此方法反映,返回 false。
返回:true 如果当前线程已中断; false 否则。

interrupt()

1. public void interrupt() {
2. if (this != Thread.currentThread())
3.             checkAccess();
4. 
5. synchronized (blockerLock) {
6. Interruptible b = blocker;
7. if (b != null) {
8.                 interrupt0();           // Just to set the interrupt flag
9.                 b.interrupt(this);
10. return;
11.             }
12.         }
13.         interrupt0();
14.     }

实例方法interrupt()仅仅是设置线程的中断状态为true,发起一个协商而不会立刻停止线程

interrupted()与isInterrupted()的区别

在这里插入图片描述方法的注释也清晰的表达了“中断状态将会根据传入的ClearInterrupted参数值确定是否重置,所以,静态方法interrupted将会清除中断状态(传入的参数ClearInterrupted为true) ,实例方法isInterrupted则不会(传入的参数ClearInterrupted为false)。

不同情况下调用interrupt()

①如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。所以,interrupt()并不能真正的中断线程,需要被调用的线程自己进行配合才行。

②如果线程处于被阻塞状态(例如处于sleep, wait, join等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。在catch块中应该加上一行代码:Thread.currentThread().interrupt();

如果不加try进行处理,发生异常以后t1线程还在继续跑的

sleep(),wait()方法抛出InterruptException异常后会清除中断标志,即把中断标志设为false。

这时你基本上阻止任何更高级别的方法/线程组注意到中断。这可能会导致问题。通过调用Thread.currentThread().interrupt(),你可以设置线程的中断标志(即把中断标志设为true),因此更高级别的中断处理程序会注意到它并且可以正确处理它。

加了try处理让他再一次进行协商

面试问问

当前线程的中断标识为true,是不是线程就立刻停止?

实例方法interrupt()仅仅是设置线程的中断状态位为true,不会停止线程。中断只是一种协商机制,修改中断标识位仅此而已,不是立刻stop打断

sleep方法抛出InterruptedException后,中断标识也被清空置为false,我们在catch没有通过调用th.interrupt()方法再次将中断标识置为true,这就导致无限循环了


相关文章
|
18天前
|
Java
线程池内部机制:线程的保活与回收策略
【10月更文挑战第24天】 线程池是现代并发编程中管理线程资源的一种高效机制。它不仅能够复用线程,减少创建和销毁线程的开销,还能有效控制并发线程的数量,提高系统资源的利用率。本文将深入探讨线程池中线程的保活和回收机制,帮助你更好地理解和使用线程池。
43 2
|
22天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
24 1
|
1月前
|
安全 Java 开发者
在多线程编程中,确保数据一致性与防止竞态条件至关重要。Java提供了多种线程同步机制
【10月更文挑战第3天】在多线程编程中,确保数据一致性与防止竞态条件至关重要。Java提供了多种线程同步机制,如`synchronized`关键字、`Lock`接口及其实现类(如`ReentrantLock`),还有原子变量(如`AtomicInteger`)。这些工具可以帮助开发者避免数据不一致、死锁和活锁等问题。通过合理选择和使用这些机制,可以有效管理并发,确保程序稳定运行。例如,`synchronized`可确保同一时间只有一个线程访问共享资源;`Lock`提供更灵活的锁定方式;原子变量则利用硬件指令实现无锁操作。
20 2
|
1月前
|
Java C++
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
33 0
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
2月前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
131 6
【Java学习】多线程&JUC万字超详解
|
3月前
|
算法 Java
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
该博客文章综合介绍了Java并发编程的基础知识,包括线程与进程的区别、并发与并行的概念、线程的生命周期状态、`sleep`与`wait`方法的差异、`Lock`接口及其实现类与`synchronized`关键字的对比,以及生产者和消费者问题的解决方案和使用`Condition`对象替代`synchronized`关键字的方法。
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
|
3月前
|
设计模式 Java 调度
JUC线程池: ScheduledThreadPoolExecutor详解
`ScheduledThreadPoolExecutor`是Java标准库提供的一个强大的定时任务调度工具,它让并发编程中的任务调度变得简单而可靠。这个类的设计兼顾了灵活性与功能性,使其成为实现复杂定时任务逻辑的理想选择。不过,使用时仍需留意任务的执行时间以及系统的实际响应能力,以避免潜在的调度问题影响应用程序的行为。
78 1
|
2月前
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
30 0
|
3月前
探索操作系统中的线程同步机制
【8月更文挑战第31天】在多线程编程领域,理解并实现线程同步是至关重要的。本文通过浅显易懂的语言和生动的比喻,带你走进线程同步的世界,从互斥锁到信号量,再到条件变量,逐步揭示它们在协调线程行为中的作用。我们将一起动手实践,用代码示例加深对线程同步机制的理解和应用。