7

我有以下配置:

<?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>

然后下面的课

public class SomeClassImpl implements SomeClass {

   @Async
   @Override // overridden from the interface
   public void doSomething(){
      System.out.println("doing something async");
   }
}

一个测试:

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

当我运行测试时,一切都按预期工作。但是后来我附加了调试器以逐步了解调用 someClass.doSomething() 时实际发生的情况,我注意到以下内容:

在此处输入图像描述

为什么 SimpleAsyncTaskExecutor 创建了 4 个线程?我知道如果我从 task:annotation-driven xml 元素中删除 executor 属性,AsyncExecutionInterceptor 将使用 SimpleAsyncTaskExecutor。但是既然我已经声明了一个任务执行器并从注释驱动的元素中引用了它,为什么要创建一个 SimpleAsyncTaskExecutor 呢?

4

1 回答 1

8

首先,如果使用 Java 5 及更高版本(Java Futures 等需要),默认的 TaskExecutor 实现应该是 ThreadPoolTask​​Executor,它与您的调试跟踪输出相匹配。这是实际执行您的测试代码的线程管理器。

SimpleAsyncTaskExecutor 可能作为 Spring 任务执行器框架的一部分启动,可能来自测试上下文文件中的另一个注释。Spring 容器可能正在启动 SimpleAsyncTaskExecutor 类的四个实例。根据 Spring 文档,这个版本的 TaskExecutor 从不重用线程来满足新请求(它将启动一个新线程):

SimpleAsyncTaskExecutor

此实现不重用任何线程,而是为每次调用启动一个新线程。但是,它确实支持并发限制,该限制将阻止任何超过限制的调用,直到插槽被释放。如果您正在寻找真正的池,请继续向下滚动页面。

参考:http ://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/scheduling.html#scheduling-task-executor

因此,这可能是测试上下文和 Spring 容器之间交互的结果。

我相信您有一个线程在这种情况下运行您的测试代码,这是您所期望的,基于单个请求。Spring TaskExecutor 实现利用了一个名为 ConcurrencyThrottleSupport 的辅助类,它应该限制(限制)正在执行的并发线程的数量。在您的情况下,这应该是 2,如 pool-size 属性所示。但是,要运行这一测试,它永远不需要分配额外的线程,并且跟踪输出与此一致。

于 2013-09-17T16:12:52.200 回答