Java: ExecutorService 错误

Java: ExecutorService error

我对 ExecutorService 有点陌生,但遇到了问题。我有这个 class:

      @Override
      public void updateAvatar(final MultipartFile multipartFile, final String speakerId) {

        final GridFS avatarGfs = new GridFS(getTemplate().getDb(), SPEAKER_AVATAR_COLLECTION);

        // Remove all sizes
        avatarGfs.remove(new BasicDBObject(SPEAKER_ID_FIELD, speakerId));
        System.out.println("hello from updateAvatar");

        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.execute(new Runnable() {
          public void run() {
            for (SpeakerAvatarSize size : SpeakerAvatarSize.values()) {
              try {

                System.out.println("calling saveAvatar");
                saveAvatar(multipartFile, speakerId, size, avatarGfs);

              } catch (IOException e) {

                LOG.error("SpeakerRepository#updateAvatar", e);
              }
            }
          }
        });

        executorService.shutdown();
        System.out.println("shut down threads");
      }

我在编辑当前用户头像以及添加另一个头像时遇到此错误。好像只加了1个头像:

Exception in thread "pool-2-thread-1" java.lang.IllegalStateException: File has been moved - cannot be read again
    at org.springframework.web.multipart.commons.CommonsMultipartFile.getInputStream(CommonsMultipartFile.java:123)
    at util.ImageScaleUtil.scale(ImageScaleUtil.java:26)
    at impl.SpeakerRepository.saveAvatar(SpeakerRepository.java:97)
    at impl.SpeakerRepository.access[=12=]0(SpeakerRepository.java:28)
    at impl.SpeakerRepository.run(SpeakerRepository.java:81)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

提前致谢!

您使用了 executor 服务,因此 saveAvatar 函数可能会 运行 在您的 updateAvater 完成后。那时,Web 框架可能已经清理了 multipartFile。

要等待执行器服务,您只需添加:

executorService.shutdown();
System.out.println("shut down threads");
try {
    executorService.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
}

顺便说一下,您创建了一个执行器服务,每个查询都有 3 个线程,并且只使用其中的一个线程。由于您必须等待任务完成,因此在那里使用执行程序服务确实没有意义。

@Override
public void updateAvatar(final MultipartFile multipartFile, final String speakerId) {

  final GridFS avatarGfs = new GridFS(getTemplate().getDb(), SPEAKER_AVATAR_COLLECTION);

  // Remove all sizes
  avatarGfs.remove(new BasicDBObject(SPEAKER_ID_FIELD, speakerId));
  System.out.println("hello from updateAvatar");

  for (SpeakerAvatarSize size : SpeakerAvatarSize.values()) {
    try {
      System.out.println("calling saveAvatar");
      saveAvatar(multipartFile, speakerId, size, avatarGfs);
    } catch (IOException e) {

      LOG.error("SpeakerRepository#updateAvatar", e);
    }
  }
}

或者如果你想将 for 循环并行到 运行,那么你可以使用 this answer:

@Override
public void updateAvatar(final MultipartFile multipartFile, final String speakerId) {

  final GridFS avatarGfs = new GridFS(getTemplate().getDb(), SPEAKER_AVATAR_COLLECTION);

  // Remove all sizes
  avatarGfs.remove(new BasicDBObject(SPEAKER_ID_FIELD, speakerId));
  System.out.println("hello from updateAvatar");

  Parallel.For(SpeakerAvatarSize.values(), size -> {
    try {
      System.out.println("calling saveAvatar");
      saveAvatar(multipartFile, speakerId, size, avatarGfs);
    } catch (IOException e) {
      LOG.error("SpeakerRepository#updateAvatar", e);
    }
  });
}