2013-07-18 59 views
2

我試圖在我的Service類中實現併發方法調用。Spring 3.x - @Async方法不會由任務執行程序同時調用

我有一些方法在我的服務類中註解爲@Async,我試圖同時調用所有這些方法。但這些方法正在順序執行。

這是我的服務類(虛設):

@Service public class TestService { 

public SomeDataType getSOmeDataType() { 
     try { 
      List<DataType> a = retrieveDataA().get(); 
      List<DataType> b = retrieveDataB().get(); 
      List<DataType> c = retrieveDataC().get(); 
      List<DataType> d = retrieveDataD().get(); 
      List<DataType> e = retrieveDataE().get();   
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     catch (ExecutionException e) { 
      e.printStackTrace(); 
     } 
     return referralDetailsReferenceData; 
    } 

@Async 
    private Future<List<DataType>> retrieveDataA() { 
     //method logic 
    } 

@Async 
    private Future<List<DataType>> retrieveDataB() { 
     //method logic 
    } 

@Async 
    private Future<List<DataType>> retrieveDataC() { 
     //method logic 
    } 

@Async 
    private Future<List<DataType>> retrieveDataD() { 
     //method logic 
    } 

@Async 
    private Future<List<DataType>> retrieveDataE() { 
     //method logic 
    } 

這是我的彈簧配置:

<bean id="executorService" class="java.util.concurrent.Executors" factory-method="newFixedThreadPool"> 
    <constructor-arg value="10" /> 
</bean> 

<task:executor id="threadPoolTaskExecutor" pool-size="10" /> 

<task:annotation-driven executor="executorService" /> 

當 「getSomeDataType」 被執行的方法的順序調用。

我是新來的@Async和在Spring中併發執行,所以我敢肯定我在做一些愚蠢的事情。但我無法弄清楚。

任何建議,非常感謝。

回答

23

問題是你在內部調用方法,所以他們沒有被代理。要使@Async正常工作,您需要從應用程序上下文中檢索對象並調用檢索到的副本上的方法。在內部調用它不起作用。

如果您嘗試調用內部@Transactional方法,則會發生同樣的情況。請參閱注意:部分末尾的Spring docs解釋@Transactional的詳細信息。

此外,您立即在Future上調用.get()返回值的方式不正確。如果您希望它們並行發生,則應提交全部任務然後通過.get()檢索每個任務。

通常的方法是處理代理問題是創建一個單獨的服務類獲得TestService注入,並調用@Async服務方法直接:

@Service public class TestServiceHelper { 
    @Autowired 
    TestService testService; 

    public SomeDataType getSOmeDataType() { 
     try { 
      // Invoke all of them async: 
      Future<List<DataType>> a = testService.retrieveDataA(); 
      Future<List<DataType>> b = testService.retrieveDataA(); 
      Future<List<DataType>> c = testService.retrieveDataA(); 
      Future<List<DataType>> d = testService.retrieveDataA(); 
      Future<List<DataType>> e = testService.retrieveDataA(); 

      // Wait for each sequentially: 
      List<DataType> aList = a.get(); 
      List<DataType> bList = b.get(); 
      List<DataType> cList = c.get(); 
      List<DataType> dList = d.get(); 
      List<DataType> eList = e.get(); 

      // do work with lists here ... 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     catch (ExecutionException e) { 
      e.printStackTrace(); 
     } 
     return referralDetailsReferenceData; 
    } 
} 

以上單獨的服務豆的替代(相當hackish /不推薦!)是將對象注入自身並使用注入的副本來調用@Async方法。

+0

嘿一個問題..我應該從我的控制器調用getSOmeDataType()嗎? – tarares

+1

是的。更一般地,你可以在任何已經注入bean TestServiceHelper的地方調用它(所以控制器或其他服務bean也是如此)。 – sehrope

+0

我試着用你在答案中描述的方式執行方法。此外,我還在方法內的每個方法的邏輯之前和之後添加了System.out.println。我收到以下輸出: 1開始**************** 1結束**************** 2開始**************** 2完**************** 3開始******* ********* 3完結**************** 4開始**************** 4結束**************** 是不是指向順序執行方法。請指教。 (抱歉,無法顯示下一行中的每個輸出..很爛) – tarares

相關問題