有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java智能方式确保Spring上下文在ThreadPoolTaskExecutor测试期间保持活动状态

我们试图在应用程序的多线程部分和数据库访问之间实现某种保证,这样数据库就不会受到太多线程的影响(客户要求),同时保持系统的其他部分充分利用必要数量的线程

设计似乎适用于(spring批处理分区+使用ThreadPoolTaskExecutor处理数据访问),但问题在于测试设计(基于http://helenaedelson.com/?p=432

现在我不得不添加线程。将(4000)睡眠到我的单元测试中,以确保在生成的额外线程完成其工作并将返回值返回主线程之前,Spring上下文不会从测试中消失

对于如何让这个测试实现得更智能,有谁有更好的想法吗

测试人员:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:partitionJdbcJob.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TaskTests {
protected static final Logger logger = LoggerFactory.getLogger(TaskTests.class);

@Autowired
private OrderServiceImpl orderService;

@Test
public void testExecution() {
    logger.info("Starting execution thread...");

    for (int i = 0; i < 8; i++) {
        orderService.dispatch();
    }

    try {
        // So that spring context is not destroyed from under the multi-threaded runnables
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

测试服务:

@Service("orderServiceImpl")
public class OrderServiceImpl {
protected static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

@Resource(name = "beanTaskExecutor")
private TaskExecutor taskExecutor;
// private AsyncTaskExecutor taskExecutor;

CompletionService completionService;

@Autowired
public void OrderServiceImpl(DataSource dataSource) {
    completionService = new ExecutorCompletionService(taskExecutor);
}

public void dispatch(final RetailPriceOptimization order) {
    logger.info("Starting dispatch execution...");

    if (this.taskExecutor != null) {
        logger.info("taskExecutor found...");
        this.taskExecutor.execute(new Runnable() {
            public void run() {
                withExecutor(order);
            }
        });
    }

    try {
        Object future1 = completionService.take().get();
        Object future2 = completionService.take().get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    logger.info("Completed dispatch execution...");
}

private void withExecutor(final RetailPriceOptimization order) {
    logger.info("Starting withExecutor execution...");

    Object result1 = completionService.submit(new Callable<String>() {
        public String call() {
            return findById("0000dd2gsl1u1546");
        }
    });
    Object result2 = completionService.submit(new Callable() {
        public Object call() {
            return orderDao.find(new Long("16"));
        }
    });
}

}


共 (2) 个答案

  1. # 1 楼答案

    现在,您的测试似乎是同步的,因为您在dispatch(...)方法中调用了completionService .take()两次。{}将等待作业完成。所以当我读到它时,你根本不需要睡觉

    而且,我认为根本没有必要使用CompletionService。你应该保留两个未来,然后一次一个地调用它们。似乎您正在等待这两个调用完成,它们将同时运行CompletionService只有当你可以立即开始处理其中一个结果时才是好的

  2. # 2 楼答案

    你不想重构你的服务

    @Service
    public class ConcurrentService{
    
        public Map<String, Object> createList(){
           this.asynCall();
        }
    
        @Async("taskExecutor")
        private Future<Map<String, Object>> asynCall(){
                //I will use submit instead of execute
                return this.taskExecutor.submit(new Callable(){
                     //Override the proper logic following interface
                 })
        .....
        }
    
    }
    

    对于所有要并行执行的进程,请使用@Async之后的新方法,这将使其异步执行。在用于合并响应或仅用于启动并行进程的方法中,请使用未来的API等待作业isDone

    boolean isDone() Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation in all of these cases, this method will return true.

    这将使人们等待所有的未来完成

    while(future1.isDone() future2.isDone()){
    //Do Something in the meanwhile
    }
    //Code will start the execution once both process are completed
    

    您可以构建一个wrap方法,使等待完成变得更容易、更动态

    Spring配置可以做到这一点:

    <task:annotation-driven executor="taskExecutor"  mode="aspectj" />
    
    <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="50" />
        <property name="maxPoolSize" value="300" />
        <property name="queueCapacity" value="30" />
    </bean>
    

    对我来说,这也是集成测试,因为您使用的是真实的对象和服务,上面的配置将导致测试在所有业务逻辑下正确执行,并将等待所有流程完成,所以您不需要有线程。在示例中的方法执行后睡眠>

    orderService.dispatch();
    

    您将能够创建资产清单,以验证流程是否按预期工作,不要忘记这是测试目的的一部分