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:
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.
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.
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
.
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
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.