首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,自己来决定自己的命运。所以,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,这就导致无限循环了