如何防止调度程序在Spring中调用异步函数的竞争状况?

时间:2019-12-04 20:38:10

标签: java spring multithreading spring-boot concurrency

我有一个功能

  @Scheduled(fixedDelayString = "2000")
  public void processPendingDownloadRequests() {
          List<DownloadRequest> downloadRequests = downloadRequestService.getPendingDownloadRequests();
          for (int i = 0; i < downloadRequests.size(); i++) {
              DownloadRequest downloadRequest = downloadRequests.get(i);
              processDownloadRequest(downloadRequest);
          }

      }
  }

这将从数据库中检索所有处于待处理状态的下载请求。这只是downloadrequest表中的一个枚举。

    @Async
    public void processDownloadRequest(DownloadRequest downloadRequest) {
        accountProfileProcessor.run(downloadRequest);
    }

在accountProfileProcessor内部,downloadRequest的状态变为InProgress。

@Scheduled函数运行并获取为异步作业提交的downloadRequest,但状态尚未切换为inProgress时,就会出现竞争条件。如何避免这种情况?

如果@Async taskexecutor队列为空但无法使其正常工作,我试图仅在@Scheduled函数中运行代码

1 个答案:

答案 0 :(得分:1)

以下内容将防止两次并发尝试下载同一资源。

请注意,如果需要确保不重复执行相同下载的后续尝试,则需要某种形式的跟踪来完成较长的时间,以某种方式防止内存泄漏(例如,不要t将所有完整ID无限期保留在内存中。

private Set<String> activeDownloads = new HashSet<>();

@Async
public void processDownloadRequest(DownloadRequest downloadRequest) {
    synchronized(this.activeDownloads) {
        if (this.activeDownloads.contains(downloadRequest.getId()) {
            // Duplicate download attempt - log it?
            return;
        } else {
            this.activeDownloads.put(downloadRequest.getId());
        }
    }


    try {
        accountProfileProcessor.run(downloadRequest);
    } finally {
        synchronized(this.activeDownloads) {
            this.activeDownloads.remove(downloadRequest.getId());
        }
    }
}