代码之家  ›  专栏  ›  技术社区  ›  duy

在Spring 4中运行并行线程的优雅方式

  •  4
  • duy  · 技术社区  · 7 年前


    我正在开发一个API。此API需要执行2 DB查询才能获得结果。
    我尝试了以下策略:

    • 在控制器中使用可调用作为返回类型。
    • 在服务中创建了2个线程(使用Callable和CountDownLatch)以并行运行2个查询并检测完成时间。

      public class PetService {
          public Object getData() {
              CountDownLatch latch = new CountDownLatch(2);
              AsyncQueryDBTask<Integer> firstQuery= new AsyncQueryDBTask<>(latch);
              AsyncQueryDBTask<Integer> secondQuery= new AsyncQueryDBTask<>(latch);
              latch.await();
      }
      
      public class AsyncQueryDBTask<T> implements Callable {
      
         private CountDownLatch latch;
      
         public AsyncQueryDBTask(CountDownLatch latch) { this.latch = latch;}
      
         @Override
         public T call() throws Exception {
          //Run query
          latch.countDown();
         }
      

    它工作得很好,但我觉得我在某处打破了弹簧的结构。

    我想知道在Spring4中获取数据的最有效方法是什么。
    -如何知道运行自己查询的两个线程都完成了它们的任务?
    -如何控制线程资源,如使用和释放线程?

    提前感谢。

    1 回复  |  直到 7 年前
        1
  •  8
  •   Laplie Anderson    7 年前

    您通常不想在ApplicationServer中创建自己的线程,也不想管理线程生命周期。在应用程序服务器中,您可以将任务提交给 ExecutorService 以汇集后台工作线程。

    方便的是,Spring具有 @Async 为您处理所有这些的注释。在您的示例中,您将创建两个返回Future的异步方法:

    public class PetService {
        public Object getData() {
            Future<Integer> futureFirstResult = runFirstQuery();
            Future<Integer> futureSecondResult = runSecondQuery();
    
            Integer firstResult = futureFirstResult.get();
            Integer secondResult = futureSecondResult.get();
        }
    
        @Async
        public Future<Integer> runFirstQuery() {
            //do query
            return new AsyncResult<>(result);
        }
    
        @Async
        public Future<Integer> runSecondQuery() {
            //do query
            return new AsyncResult<>(result);
        }
    }
    

    只要您配置 ThreadPoolTaskExecutor 并启用异步方法,Spring将为您处理提交任务。

    注: get() 方法阻塞当前线程,直到工作线程返回结果,但不阻塞其他工作线程。通常建议设置一个超时以防止永远阻塞。