|面试必须要掌握的内容:多线程与Spring容器事务机制( 二 )


   
   <b>public</b> ProcessingServiceParallelRunDecorator(ProcessingService delegate) {
       <b>this</b>.delegate = delegate;
   

   </font><font><i>/**
    * In a real scenario it should be an external configuration
    */</i></font><font>
   <b>private</b> <b>int</b> batchSize = 10;

   @Override
   <b>public</b> List<Integer> processObjects(List objectIds) {        List<List<Integer>> chuncks = getBatches(objectIds batchSize);        List<List<Integer>> processedObjectIds = chuncks.parallelStream().map(delegate::processObjects)
               .collect(Collectors.toList());

       <b>return</b> flatList(processedObjectIds);
   

   <b>private</b> List<List<Integer>> getBatches(List collection <b>int</b> batchSize) {
       <b>return</b> IntStream.iterate(0 i -> i < collection.size() i -> i + batchSize)
               .mapToObj(i -> collection.subList(i Math.min(i + batchSize collection.size())))
               .collect(Collectors.toList());
   

   <b>private</b> List<Integer> flatList(List> listOfLists) {
       <b>return</b> listOfLists.stream().collect(ArrayList::<b>new</b> List::addAll List::addAll);
   
</font>

实际的调用被委托给一个处理服务的实现 , 但Decorator负责跨线程的工作分配和收集结果 。
装饰器模式的实现使客户端代码不知道实际的实现 。 可以直接注入单线程版本 , 也可以注入多线程版本 , 而无需直接改变客户端代码 。
为了理解客户端代码可能是什么样子的 , 让我们看一下一个简单的单元测试 。
@RunWith( SpringJUnit4ClassRunner.<b>class</b> )
@SpringBootTest(properties = { <font>\"service.parallel=false\"</font><font> )<b>public</b> <b>class</b> ProcessingServiceTest {
   
   @Autowired
   ProcessingService processingService;
   
   ProcessingService processingServiceDecorator;
   
   @Test    <b>public</b> <b>void</b> shouldRunParallelProcessingUsingDecorator() {
       processingServiceDecorator = <b>new</b> ProcessingServiceParallelRunDecorator(processingService);
       List objectIds = Arrays.asList(<b>new</b> Integer[
{ 1 2 3 4 5 6 7 8 9 10 11 12);
       
       List resultList = processingServiceDecorator.processObjects(objectIds);
       
       Assert.assertEquals(objectIds resultList);
   
   
</font>

该代码传递了一个objectIds的列表 , 并运行测试中明确创建的Decorator服务 。
预计由于内部配置的chunk大小为10 , 两个线程将处理数据 。 通过检查日志 , 我们可以看到以下几行 。
【|面试必须要掌握的内容:多线程与Spring容器事务机制】ProcessingDBService: Running in thread ForkJoinPool.commonPool-worker-3 with object ids [1 2 3 4 5 6 7 8 9 10
ProcessingDBService: Running in thread main with object ids [11 12


在正好两个线程中 , 并行流使用主线程进行处理 , 第二个线程在它们之间分配工作 。