每天学习一点点之从 SonarQube Bug 看对线程中断异常的处理

最近在基于 SonarQube 对代码进行质量优化,说实话,之前觉得 SonarQube 这种很无聊,但最近静下心来看了一些扫描出来的问题后,发现这种工具作用还是挺大的,能够帮助我们找到代码中的隐藏缺陷,从而夯实基础。本文的议题就是基于 SonarQube Bug 探讨一下线程中断。

在 SonarQube 中的异常为“InterruptedException should not be ignored“:
在这里插入图片描述

即 SonarQube 认为 InterruptedException 异常不应该被忽视,即本文探讨的关键点就是 InterruptedException 异常该如何处理。

理解线程中断

线程中断我觉得有这么几个关键点:

  • 中断线程靠的是一个状态标识位
  • 标识位的状态传递涉及到线程间的通讯协作
  • Java 提供了原生 API 帮助我们传递、判断这个状态,一般也建议平时就使用这些 API 来操作线程中断

InterruptedException

关于 InterruptedException 我觉得有这么几个关键点:

  • 如果线程执行了如下几个底层方法,当线程被中断时,会抛出 InterruptedException

    java.lang.Object#wait()
    java.lang.Object#wait(long)
    java.lang.Object#wait(long, int)
    java.lang.Thread#sleep(long)
    
  • 抛出 InterruptedException 后会清除中断标识位

  • 属于 CheckedException,强制需要捕获处理

处理 InterruptedException

关于处理 InterruptedException,我觉得关键点在于开发者是否希望上层调用方感知当前线程的中断状态,因为(常规情况下)只有当前线程被中断了才会抛出这个异常,线程中断是一种状态,那么这种状态是否需要传递给上层调用方呢。

很明显 SonarQube 是不赞成忽视 InterruptedException 的。忽视 InterruptedException 会造成一个问题:线程中断的状态丢失,上层调用方将无法感知。

换句话来说,如果你觉得上层调用方没必要感知线程的中断状态,那么你可以忽视它(当然可能显得政治不正确);如果要感知中断状态,要么抛出 InterruptedException 交给上层处理或者 catch 后执行 java.lang.Thread#interrupt设置中断状态即可。

回到本次扫描的异常代码,其实就是想注册一个钩子做一些后续工作,不存在中断状态的感知问题,所以我个人认为其实不手动设置中断状态也 问题不大。

 Runnable shutdownHook = () -> {
            try {
                //do sth
                Thread.sleep(dubboShutdownWait);
                 //do sth
            } catch (InterruptedException e) {
                log.error(e);
                //Thread.currentThread().interrupt();
            }
        };
        Runtime.getRuntime().addShutdownHook(new Thread(shutdownHook));

而且还有个细节点,这里无非就是想让线程等会,干嘛非得用 java.lang.Thread#sleep(long) 方法呢,还得处理 InterruptedException,用 java.util.concurrent.locks.LockSupport#parkNanos(long) 不香嘛?

或者是不是也可以这样(就是玩):

    private static void workTime(long ms) {
        final long l = System.currentTimeMillis();
        while (System.currentTimeMillis() <= l + ms) {
        }
    }

附:完整 SonarQube 描述

为了便于后续查阅,这里完整贴出 SonarQube 的描述:

“InterruptedException” should not be ignored

InterruptedExceptions should never be ignored in the code, and simply logging the exception counts in this case as “ignoring”. The throwing of the InterruptedException clears the interrupted state of the Thread, so if the exception is not handled properly the fact that the thread was interrupted will be lost. Instead, InterruptedExceptions should either be rethrown - immediately or after cleaning up the method’s state - or the thread should be re-interrupted by calling Thread.interrupt() even if this is supposed to be a single-threaded application. Any other course of action risks delaying thread shutdown and loses the information that the thread was interrupted - probably without finishing its task.

Similarly, the ThreadDeath exception should also be propagated. According to its JavaDoc:

If ThreadDeath is caught by a method, it is important that it be rethrown so that the thread actually dies.

Noncompliant Code Example

public void run () {
  try {
    while (true) {
      // do stuff
    }
  }catch (InterruptedException e) { // Noncompliant; logging is not enough
    LOGGER.log(Level.WARN, "Interrupted!", e);
  }
}

Compliant Solution

public void run () {
  try {
    while (true) {
      // do stuff
    }
  }catch (InterruptedException e) {
    LOGGER.log(Level.WARN, "Interrupted!", e);
    // Restore interrupted state...
    Thread.currentThread().interrupt();
  }
}

See

References

  • https://blog.csdn.net/Dongguabai/article/details/110338023

欢迎关注公众号:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值