所以,我遇到了一个问题,由于InterruptedExceptions处理不当,Sonar Qube正在标记我的代码.精确的Sonar Qube误差为java:S2142,可在此处找到:https://github.com/joansmith/sonar-java/blob/master/java-checks/src/main/resources/org/sonar/l10n/java/rules/squid/S2142.html

我的代码如下-Sonar Qube将extractFutureIntoList()中可能InterruptedExceptions的处理标记为问题的根源:

@Service
@Log4j2
public class AsynchronousDataGrabber {

  ExecutorService executorService = Executors.newFixedThreadPool(10);

  public List<MyDataObject> getDataAsynchronously() {
    Optional<Future<MyDataObject>> future01 = getDataFuture("01");
    Optional<Future<MyDataObject>> future02 = getDataFuture("02");
    Optional<Future<MyDataObject>> future03 = getDataFuture("03");

    List<MyDataObject> list = new ArrayList();
    
    extractFutureIntoList(future01, list);
    extractFutureIntoList(future02, list);
    extractFutureIntoList(future03, list);
    
    return list;
  }


  private Optional<Future<MyDataObject>> getDataFuture(String key) {
    try {
      return Optional.of(executorService.submit(() -> getDataFromRemoteApi(key)));
    } catch(Exception e) {
      log.error("Exception", e);
      return Optional.empty();
    }
  }
  
  private void extractFutureIntoList(Optional<Future<MyDataObject>> future, List<MyDataObject> list) {
    try {
      if (future.isPresent()) {  
        // This is apparently where the `InterruptedException` can occur - Future.get()
    list.add(future.get().get());  
      }
    } catch (Exception e) {
      // SonarQube is telling me that merely logging an `InterupptedException` is not enough
      // Apparently, I must either rethrow the `InterruptedException`,
      //or call `Thread.currentThread().interrupt()
      log.error("Exception", e);
      return;   
    }
  }
}

声纳Qube建议我解决这个问题,要么重新抛出InterruptedException,要么拨打Thread.currentThread().interrupt()--每当Future.get()被打断时.

我的问题是,我的应用程序的主线程正在调用getDataAsynchronously().如果对InterruptedException的唯一可接受的响应是重新抛出它或中断当前线程,那么executorService's个线程中的一个中断就会导致整个应用程序崩溃.这似乎是一个过度的响应,特别是考虑到由线程getDataFromRemoteApi()运行的任务无论如何可能并不总是成功的.

有没有更好的方法来处理InterruptedException-理想的是Sonar Qube可以接受的方法,但不涉及杀死试图调用Future.get()的线程?

我试过记录InterruptedException米(log.error("Exception", e);米),我试图抓住InterruptedException米(throw new RuntimeException(e);米)并重新抛出--都没有安抚索纳尔·奎比.

推荐答案

你真的永远不应该忽视InterruptedException.

RIST InterruptedException表示正在运行的线程被标记为中断,该信号(可以用Thread.currentThread.isInterrupted()判断)被接收到,并且是removed.因此,在不呕吐/拨打Thread.currentThread().interrupt()的情况下抓住它会导致永远忘记中断的事实.

如果捕捉到InterruptedException,则从方法中优雅地返回并抛出异常,或者恢复标志并返回.

在您的特定情况下,在指定的行中获得InterruptedException表示您的main线程已被中断(而不是执行器的线程).这意味着有人停止了程序,因此对方法返回值不再感兴趣.我建议你要么:

  1. 先打Thread.currentThread().interrupt(),然后打throw new RuntimeException(e).这没问题--你们都保留了中断的标志,并表示getDataAsynchronously()没有正确执行,没有答案可以返回.
  2. 尽最大努力--拨打Thread.currentThread().interrupt(),然后从extractFutureIntoList返回.您的程序将继续执行剩余的extractFutureIntoList个调用.如果任何其他期货已经完成,因此它们的结果立即可用,则future.get()将返回计算结果,而不会抛出InterruptedException.因此,您将从线程中断时刻完成的所有期货收集数据.这将是一种优雅的停摆.
  3. 如果可能--将getDataAsynchronously标记为throws InterruptedException并重新抛出异常.这是一个最佳实践--将任何阻塞方法标记为throws InterruptedException.你的方法getDataAsynchronously是阻塞的,实际上意味着要抛出它.

Java相关问答推荐

在现代操作系统/硬件上按块访问数据值得吗?

使用标记时,场景大纲不在多个线程上运行

使用联接和分页的SpringBoot Spring数据JPA

Java记录的不同序列化/反序列化

我需要生成一个文件来整合每个特性执行的所有JSON结果

获取字符串中带空格的数字和Java中的字符

暂停计时器

如何解释Java中for-each循环中对Iterable的强制转换方法引用?

为什么同步数据块无效?

Spring Boot&;Docker:无法执行目标org.springframework.boot:spring-boot-maven-plugin:3.2.0:build-image

Java堆中的许多java.time.ZoneRegion实例.ZoneId实例不应该被缓存吗?

插入中的JOOQ序列,设置为VS值

从12小时开始的日期模式

有没有办法在o(log(N))中以系统的方式将数组中的小块元素复制和移动到新增长的数组中的左侧?

在Java中将.GRF转换为图像文件

";home/runner/work/中没有文件...匹配到[**/pom.xml];Maven项目的构建过程中出现错误

如何设置默认序列生成器分配大小

如何正确使用java.time类?

始终使用Spring Boot连接mongodb上的测试数据库

为什么单例实例持有者的循环引用不会抛出 StackOverflowError?