0

I am a bit new to the ExecutorService, and I am having a problem with it. I have this 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");
      }

And I get this this error when editing a current user avatar and also when adding another avatar. It seems that only 1 avatar is added:

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$000(SpeakerRepository.java:28)
    at impl.SpeakerRepository$1.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)

Thank you in advance!

hagrawal7777
  • 14,103
  • 5
  • 40
  • 70
Deniss M.
  • 3,617
  • 17
  • 52
  • 100

1 Answers1

1

You use executor service, so the saveAvatar function will run potentially after your updateAvater finished. At that time, the web framework might already cleaned up multipartFile.

To await the executor service, you can simply add:

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

By the way, you create an executor service with 3 threads on every query, and use only one thread of them. Since you have to wait for the task to finish, there is really no point in using an executor service there.

@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);
    }
  }
}

Or if you wanted the for loop to run in parallel, then you can use 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);
    }
  });
}
Community
  • 1
  • 1
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97
  • Thank you!!!! No more errors. I am quite new to multitasking and I am just trying to optimise the upload. I cannot use Java 8 in the project, and I have to use executorService. I would be very thankful if you can tell me how to optimise my code to optimise the upload :) – Deniss M. Dec 13 '15 at 15:11
  • So do you mean to scale the images in parallel? Is it slow now? – Tamas Hegedus Dec 13 '15 at 15:42
  • it is not slow, but needs to be faster. Yes that's what I mean. Thank you :) – Deniss M. Dec 13 '15 at 15:51
  • Then implement Callable, create a list of tasks, and use executorService.invokeAll. That is a lot of code, maybe you want to post a new question, or search for "parallel for each in java 7". Parallelism in Java 7 is a pain in the a**. (In java 8 it's a little bit better but still painful) – Tamas Hegedus Dec 13 '15 at 16:36
  • hmm. Well then I will just leave it as it is for now, and consult further on how to handle this case. Thanks a lot. Your suggestion helped me get rid of the error and now the edit/save process is working fine. Thanks again. – Deniss M. Dec 13 '15 at 17:20