Multithreading in spring

Elis.jane picture Elis.jane · Apr 7, 2015 · Viewed 29.3k times · Source

I am trying to get into spring multithreading and I have few questions.

I have runnable method in ThreadRating class. Now I am not sure about the best way of using it.

option 1 I found:

private void updateRating() {
        ExecutorService executor = Executors.newFixedThreadPool(10);

    for (int i = 0; i < 10; i++) { // test
        // thread part
        Runnable worker = new ThreadRating(path, i, products.get(i), dao, fileHandler);
        executor.execute(worker);
    }
    executor.shutdown();
    try {
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
        log.error("There was an error when ending threads");
        System.exit(1);
    }
    System.out.println("Finished all threads");
}

This seem to be running fine. After the for loop, it waits until threads are finished and ends.

Second option I tried

private TaskExecutor taskExecutor;

public UpdateBO(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
}

private void updateRating() {
        for (int i = 0; i < 10; i++) { // test
            Runnable worker = new ThreadRating(path, i, products.get(i), dao, fileHandler);
            taskExecutor.execute(worker);
        }
    // wait for threads to be finished before you go any further ??
        }

And in xml file I have

<beans:bean id="taskExecutor"
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <beans:property name="corePoolSize" value="5" />
    <beans:property name="maxPoolSize" value="10" />
    <beans:property name="queueCapacity" value="25" />
    <beans:property name="waitForTasksToCompleteOnShutdown" value="true" />
</beans:bean>

<beans:bean id="updateBO" class="UpdateBO">
    <beans:constructor-arg ref="taskExecutor" />
</beans:bean>

And here are my questions:

  1. Is there any difference between these two options? Speed, memory, possible leaks? Or are they the same just written differently?
  2. Do I need to shutdown the pool when using webservice? I know that in the second option I don't have to, but is it the same when using webservice?
  3. When using second option - how should I tell to wait there until all jobs are finished? In the first option I just shut the pool down and wait to finish. But in the second option the code request is finished before the tasks are completed.
  4. executor.execute(worker); - just to clarify. This is not actually creating a new thread, but it adds task to a queue and if the queue is full it waits right on this line in the code until there is free place?

Thanks for helping me understand.

Answer

Alex Salauyou picture Alex Salauyou · Apr 7, 2015
  1. Main difference: in option 1) you create new executor on every updateRating() call, in option 2) executor is created once on deployment time, you feed the same single executor with new jobs. Second approach is much better.

  2. Why do you need to shut down the executor? Creating new executors and shutting them down to wait until task is processed is antipattern. Remember, that executors are created in order to control system resources and should be treated such. (E. g. you have DB connection pool of 50 connections - so to serve DB access you create executor of 50 threads - to avoid connection limit exceed. Or you have 24 cores on server and need to parallelize work in the best possible way).

    And, as I mentioned in comment, in some environments (such as app servers) you often have no rights to shut down executor. Such attempt will produce SecurityException.

  3. If you need to wait until workers finish their jobs, wrap every job with Callable instead of Runnable, then from main thread call corresponding future.get() - and it will block until job finishes. Timeouts are supported. Example

  4. Absolutely right. Threads are created and destroyed by executor itself, when it thinks is best time to. Try to monitor your app with jvisualvm to see how it happens.