在java中,阻塞的线程可以打断后继续执行,线程打断前后会有一个打断状态的变化,这个状态会影响park方法的使用,本文主要介绍java打断状态相关的内容。

1、打断阻塞的线程
线程阻塞有很多情况,比如没有获取到锁、执行sleep、执行join等,下面以sleep为例:

Thread t1 = new Thread(() -> {
          try {
              TimeUnit.SECONDS.sleep(5);
          } catch (InterruptedException e) {
              System.out.println("02-------线程t1被打断");
              e.printStackTrace();
          }
          System.out.println("03--t1的打断状态-:"+Thread.currentThread().isInterrupted());
          //开始循环,直到线程被打断后,打断标记变为true才停止
          for (;;){
              if (Thread.currentThread().isInterrupted())
                  break;
          }
          System.out.println("04-------t1的打断状态-:"+Thread.currentThread().isInterrupted());

          System.out.println("05--t1的打断状态-:"+Thread.interrupted());
          //继续瞓5s
          try {
              TimeUnit.SECONDS.sleep(5);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println("06----Thread.interrupted()过后---t1的打断状态-:"+Thread.currentThread().isInterrupted());

          System.out.println("07-------t1 over");
      }, "t1");

  //启动线程t1
  t1.start();

  TimeUnit.SECONDS.sleep(2);
  System.out.println("01--t1的打断状态-:"+t1.isInterrupted());

  //打断sleep阻塞状态的线程
  t1.interrupt();

  TimeUnit.SECONDS.sleep(2);

  //打断非阻塞状态的线程
  t1.interrupt();
//输出
01--t1的打断状态-:false
02-------线程t1被打断
03--t1的打断状态-:false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.iwat.arithmetic.leetcode.Q452.lambda$main$0(Q452.java:44)
	at java.lang.Thread.run(Thread.java:748)
04-------t1的打断状态-:true
05--t1的打断状态-:true
06----Thread.interrupted()过后---t1的打断状态-:false
07-------t1 over

方法介绍:

  • interrupt():打断某一线程,
  • 如果线程阻塞==(sleep、join、await没有结束,任务调度器不会考虑阻塞的线程)==,会抛出异常。并且将线程的阻塞标记改为false,然后继续运行。注意:锁的作用时阻塞进程,阻塞进程有很多种方式,无论什么原因造成的阻塞,任务调度器都不会考虑阻塞的线程
  • 如果线程正常运行,会将线程的阻塞标记改为ture,然后继续运行。
  • isInterrupted():返回当前线程的打断标记
  • static interrupted():返回当前线程的打断标记,同时将打断标记改为false(只能在线程内部执行),方法如下:
public static boolean interrupted() {
        return currentThread().isInterrupted(true);
}

线程的打断状态变化:

  • 默认时false
  • 阻塞被打断仍是false
  • 非阻塞状态执行interrupt(),阻塞状态变为true
  • 执行static interrupted(),阻塞状态变为false

2、park方法的使用
LockSupport.park()会阻塞线程,生效的条件时阻塞状态为false,当阻塞状态为true时,方法无效无法阻塞线程。

Thread t1 = new Thread(()->{
           log.info("01------parking...");

           LockSupport.park();
           log.info("02------unpark");
           log.info("03------t1的打断状态"+Thread.currentThread().isInterrupted());
           //如果打断标记已经是 true, 则 park 会失效
           LockSupport.park();
           log.info("04-------unpark");
       },"t1");
       t1.start();

       TimeUnit.SECONDS.sleep(3);
       log.info("t1的打断状态"+t1.isInterrupted());
       //打断park
       t1.interrupt();
//输出
2023-03-04 08:36:46.518 [t1] INFO -- 01------parking...
2023-03-04 08:36:49.522 [main] INFO -- t1的打断状态false
2023-03-04 08:36:49.522 [t1] INFO -- 02------unpark
2023-03-04 08:36:49.522 [t1] INFO -- 03------t1的打断状态true
2023-03-04 08:36:49.523 [t1] INFO -- 04-------unpark

从打印时间可以看到第二个park没有生效。