I have the following configutation:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<context:component-scan base-package="com.abc" />
<task:annotation-driven executor="executor"/>
<task:executor id="executor" pool-size="2"/>
</beans>
Then the following class
public class SomeClassImpl implements SomeClass {
@Async
@Override // overridden from the interface
public void doSomething(){
System.out.println("doing something async");
}
}
A test:
@ContextConfiguration("classpath:test-config.xml") // with the xml config above
@RunWith(value = SpringJUnit4ClassRunner.class)
public class SomeClassTest {
@Autowired
private SomeClass someClass;
@Test
public void testSomething() throws Exception {
System.out.println("Calling doSomething");
someClass.doSomething();
Thread.sleep(5000);
}
}
When I ran the test, everything worked as expected. But then I attached the debugger to step through what is actually happening when someClass.doSomething() is called and i noticed the following:
Why is it that 4 threads are being created by a SimpleAsyncTaskExecutor? I know that if I remove the executor property from the task:annotation-driven xml element, the AsyncExecutionInterceptor will use the SimpleAsyncTaskExecutor. But since I have declared a task executor and referenced it from the annotation-driven element, why is a SimpleAsyncTaskExecutor being created?
First of all, if using Java 5 and above (required for Java Futures, etc), the default TaskExecutor implementation should be the ThreadPoolTaskExecutor, which matches your debug trace output. This is the thread manager actually executing your test code.
The SimpleAsyncTaskExecutor is likely being launched as part of the Spring task executor framework, possibly from another annotation in your test context file. The Spring container may be launching four instances of the SimpleAsyncTaskExecutor class. According to Spring documentation, this version of the TaskExecutor never re-uses threads to satisfy new requests (it will start a new thread):
SimpleAsyncTaskExecutor
This implementation does not reuse any threads, rather it starts up a new thread for each invocation. However, it does support a concurrency limit which will block any invocations that are over the limit until a slot has been freed up. If you're looking for true pooling, keep scrolling further down the page.
Therefore, this could be the result of interactions between the test context and the Spring container.
I believe you have a single thread running your test code in this scenario, which is what you expect, based on a single request. Spring TaskExecutor implementations leverage a helper class called ConcurrencyThrottleSupport which is supposed to throttle (limit) the number of concurrent threads in execution. In your case, this should be 2, as indicated by the pool-size property. However, to run this one test, it should never need to allocate an additional thread, and the trace output agrees with this.