1. 面试不多,难度低,但是容易混淆
  2. 此处线程的“打断”不是把线程打折腿
  3. 不是线程的停止与中断
  4. 名字不好===>容易混淆

线程打断的3个方法

  1. 不是特别重要
  2. 第一个比后两个重要,第一个除了可以配合对于这个标志位的检查,能正确结束一个线程之外也不是很重要
  3. 读jdk源码时,可能会碰到线程打断相关的知识点,所以要知道

interrupt()

  • t.interrupt()设中断标志位
  • 打断某个线程(设置标志位===>有没有被打断过、有没有被申请打断过)
  • 原来是false,调用该方法给标志位设成true
  • 只是申请一下,设置一下标志位,只是给了线程一个信(号),至于线程收到这个信(号)之后要不要处理,该如何处理,这要看线程自身,看自己如何安排
  • 只是设置了线程自带的一标志位,不进行物理上的变化

    isInterrupted()

  • 查询某线程是否被打断过(查询标志位)

  • 是否被设置过那个标志位
  • 设过了来查,没设过来查

static interrupted()

  • 查询当前线程当前正在执行的线程RUNNING)是否被打断过,并重置打断标志
  • 容易与第二个混淆,不需要线程对象,直接用类调用即可
  • 查询是否被设置过标志位,假如设置过了(标志位为true),就重置标志位===>即将标志位设回为false

代码示例

SleepHelper帮助类(只是简答地将try……catch……扔到帮助类中)

在演示式的代码中写很多try……catch……,看起来费劲

  1. package com.mashibing.util;
  2. import java.util.concurrent.TimeUnit;
  3. public class SleepHelper {
  4. public static void sleepSeconds(int seconds) {
  5. try {
  6. TimeUnit.SECONDS.sleep(seconds) ;
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }


interrupt()与isInterrupted()

  1. 线程结束可以采用这种方法
  2. 设置一个循环,每一次循环都检查一下是否有人设置了标志位;假如有人设置了,就可以退出循环(break),结束线程===>优雅地结束线程的方案
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. /**
  4. * interrupt()与isInterrupted()
  5. * 设置标志位 + 查询标志位
  6. */
  7. public class T05_Interrupt_and_isInterrupted {
  8. public static void main(String[] args) {
  9. Thread t = new Thread(() -> {
  10. for (; ; ) {
  11. // 查询出来后并不能将标志位重置
  12. if (Thread.currentThread().isInterrupted()) {
  13. System.out.println("Thread is interrupted!");
  14. System.out.println(Thread.currentThread().isInterrupted());
  15. // break;
  16. }
  17. }
  18. });
  19. t.start();
  20. // 两秒后设中断标志位
  21. SleepHelper.sleepSeconds(2);
  22. t.interrupt();
  23. }
  24. }

interrupt与interrupted()

  1. interrupted()方法是一个静态成员变量(静态方法),拿的是当前线程
  2. interrupted()方法返回当前标志位的状态并将标志位复位(恢复)
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. /**
  4. * interrupt与interrupted()
  5. */
  6. public class T06_Interrupt_and_interrupted {
  7. public static void main(String[] args) {
  8. Thread t = new Thread(() -> {
  9. for (; ; ) {
  10. if (Thread.interrupted()) {
  11. System.out.println("Thread is interrupted!");
  12. System.out.println(Thread.interrupted());
  13. }
  14. }
  15. });
  16. t.start();
  17. SleepHelper.sleepSeconds(2);
  18. t.interrupt();
  19. //思考一下,如果在这里写
  20. System.out.println("main: " + t.interrupted());
  21. //输出的是哪个线程的中断状态
  22. // 输出false,虽然写的是t.interrupt,但是由于这个方法interrupted()是一个静态成员变量(静态方法),拿的是当前线程;这里的当前线程是主线程
  23. }
  24. }

interrupt与sleep() wait() join()

  1. 在sleep时、wait时、join时,一旦对其设置了标志位(interrupt打断了线程),就会抛(出)异常InterruptedException
  2. 抛出这个异常之后,下一步怎么处理;
    1. 要不要catch,还是throws
    2. catch之后如何处理
    3. 主动权还是在线程本身
  3. 在不间断运行的服务器里,如果有sleep方法(不建议有)、wait方法(这个有可能有)、join方法(也很少用),要想用interrupt方法让他停止的话,必须得catch住interrupt异常,然后对异常做出正确的响应===>应用程序要退出,记录日志退出;忽略这个异常,继续向下执行,循环;这个主要交给写程序的程序员处理了,没有固定的处理方式;看了这个异常怎么处理是自己的事情,并不是一打断就会终止线程
  4. (一旦抛出InterruptException的异常之后)catch住exception之后,默认情况下,java会自动地将(中断)标志位复位===>既然已经catch住了,说明你要处理了,赶紧给你复位复回去,以免别人再次打断,那个打断状态抓不着
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. /**
  4. * interrupt与sleep() wait() join()
  5. */
  6. public class T07_Interrupt_and_sleep {
  7. public static void main(String[] args) {
  8. Thread t = new Thread(() -> {
  9. try {
  10. Thread.sleep(10000);
  11. } catch (InterruptedException e) {
  12. System.out.println("Thread is interrupted!");
  13. System.out.println(Thread.currentThread().isInterrupted());
  14. }
  15. });
  16. t.start();
  17. SleepHelper.sleepSeconds(5);
  18. t.interrupt();
  19. }
  20. }
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. /**
  4. * interrupt与sleep() wait() join()
  5. */
  6. public class T08_Interrupt_and_wait {
  7. private static Object o = new Object();
  8. public static void main(String[] args) {
  9. Thread t = new Thread(() -> {
  10. synchronized (o) {
  11. try {
  12. o.wait();
  13. } catch (InterruptedException e) {
  14. System.out.println("Thread is interrupted!");
  15. System.out.println(Thread.currentThread().isInterrupted());
  16. }
  17. }
  18. });
  19. t.start();
  20. SleepHelper.sleepSeconds(5);
  21. t.interrupt();
  22. }
  23. }

interrupt与synchronized

  1. 打断一个线程能不能将一个正在竞争锁、争抢锁的线程给打断,会不会抛异常
  2. 不可能,不会抛异常和打断线程
  3. 线程在争抢锁的过程中是不可能被interrupt打断或者干扰掉的
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. /**
  4. * interrupt与synchronized
  5. */
  6. public class T09_Interrupt_and_sync {
  7. private static Object o = new Object();
  8. public static void main(String[] args) {
  9. Thread t1 = new Thread(() -> {
  10. synchronized (o) {
  11. // sleep方法不会释放锁,10s内这把锁归t1所有
  12. SleepHelper.sleepSeconds(10);
  13. }
  14. });
  15. t1.start();
  16. SleepHelper.sleepSeconds(1);
  17. Thread t2 = new Thread(() -> {
  18. // t2去抢那把锁,只有等t1线程执行完了才能抢到,那么这是能将线程打断吗?
  19. synchronized (o) {
  20. }
  21. System.out.println("t2 end!");
  22. });
  23. t2.start();
  24. SleepHelper.sleepSeconds(1);
  25. // 只是设标志位,不是将线程打折腿
  26. // 设标志位之后该抢锁还是得抢锁,不会理会标志位设不设
  27. t2.interrupt();
  28. }
  29. }

interrupt与lock

  1. 设标志位能不能干扰(最好不要说打断)juc中的ReentrantLock这种新型的锁
  2. 经验证,也不会干扰到
  3. 如果说有一个线程持有了一把锁总是不释放,另外一个线程去申请这把锁的时候,中间过程是干扰(interrupt)不到的
  4. 像干扰到怎么做===>lock与synchronized的重要区别,lock可以使用lockInterruptibly()方法
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * interrupt与lock
  6. */
  7. public class T10_Interrupt_and_lock {
  8. private static ReentrantLock lock = new ReentrantLock();
  9. public static void main(String[] args) {
  10. Thread t1 = new Thread(() -> {
  11. lock.lock();
  12. try {
  13. Thread.sleep(10000);
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. } finally {
  17. lock.unlock();
  18. }
  19. System.out.println("t1 end!");
  20. });
  21. t1.start();
  22. SleepHelper.sleepSeconds(1);
  23. Thread t2 = new Thread(() -> {
  24. lock.lock();
  25. try {
  26. } finally {
  27. lock.unlock();
  28. }
  29. System.out.println("t2 end!");
  30. });
  31. t2.start();
  32. SleepHelper.sleepSeconds(1);
  33. t2.interrupt();
  34. }
  35. }

interrupt与lockInterruptibly()

  1. 解决interrupt不能干扰到lock锁住的线程的问题
  2. 线程在抢锁的过程中还盯着有没有人设自己的标志位,如果有人设自己的标志位,则抛异常
  3. catch住异常之后怎么处理,是继续抢这把锁,还是要放弃了,交给线程,交给程序员自己处理
  4. 如果想打断锁争抢的过程,如果想允许interrupt方法干扰抢锁过程,用ReentrantLock中的lockInterruptibly方法
  1. package com.mashibing.juc.c_000_threadbasic;
  2. import com.mashibing.util.SleepHelper;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * interrupt与lockInterruptibly()
  6. */
  7. public class T11_Interrupt_and_lockInterruptibly {
  8. private static ReentrantLock lock = new ReentrantLock();
  9. public static void main(String[] args) {
  10. Thread t1 = new Thread(() -> {
  11. lock.lock();
  12. try {
  13. SleepHelper.sleepSeconds(10);
  14. } finally {
  15. lock.unlock();
  16. }
  17. System.out.println("t1 end!");
  18. });
  19. t1.start();
  20. SleepHelper.sleepSeconds(1);
  21. Thread t2 = new Thread(() -> {
  22. System.out.println("t2 start!");
  23. try {
  24. // 可以被打断的过程
  25. lock.lockInterruptibly();
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. } finally {
  29. lock.unlock();
  30. }
  31. System.out.println("t2 end!");
  32. });
  33. t2.start();
  34. SleepHelper.sleepSeconds(1);
  35. t2.interrupt();
  36. }
  37. }

总结

  1. interrupt有一个很好的作用===>优雅地中断一个线程(中断线程有好多种方法)