2011-11-30 18 views
1

我知道App Server負責處理線程,因此開發人員應該只專注於業務邏輯... 但考慮一個示例。無狀態的EJB有一個CountManager類型的成員。何時需要注意EJB中的多線程?

@WebService 
@Stateless 
public class StatelessEJB { 
    private CountManager countManager; 
    ... 
    public void incrementCount() {countManager.incrementCount();} 
    public int getCount(){return countManager.getCount();} 
} 

而且CountManager

public class CountManager { 
    public void increaseCount() { 
    // read count from database 
    // increase count 
    // save the new count in database table. 
    } 

    public int getCount() { 
    // returns the count value from database. 
    } 
} 

開發商應該考慮線程多在這裏。如果你讓CountManager也是一個EJB,我想問題不會消失。 開發人員需要注意的一般準則是什麼?

更新: 更改了代碼。假設EJB的方法暴露爲web服務,所以我們無法控制客戶端調用它們的順序。交易屬性是默認的。此代碼在多線程場景下的行爲是否正確?

+0

描述你爲什麼說「這段代碼不是線程安全的」。你正在執行什麼操作,按照什麼順序以及你期望的結果?你擔心EJB併發訪問還是併發數據庫訪問?你使用默認的EJB TransactionAttributes嗎? –

+0

@PiotrNowicki更新了這個問題,刪除了你提到的陳述。我擔心結果不正確 – anergy

回答

2

EJB是線程安全的並不意味着不同的方法調用將爲您提供一致的結果。

EJB給你,在你特別EJB實例每一個方法恰好一個線程執行的確定性。這不會節省您訪問訪問EJB的不同實例的多個用戶以及不一致的結果危險。

CountManager您的CountManager似乎是一個普通的Java類,這意味着您在無狀態EJB中擁有一個狀態。這樣做不好,EJB線程安全不會在這種情況下保護您免受任何困擾。您的對象可以同時通過多個EJB實例訪問。

客戶的第一個方法調用StatelessEJB.incrementCount()(它啓動一個事務 - 默認TransactionAttribute)之間,以及第二客戶端的方法調用StatelessEJB.getCount()(這將啓動交易)很多事情都有可能發生,在count的值可以改變。

如果您將其更改爲EJB,我認爲您不會更安全。如果它是SLSB而不是它還沒有任何狀態。如果狀態不是作爲EJB字段變量實現,而是作爲數據庫獲取數據,那麼它肯定會更好,但仍然存在 - 事務對您來說不是一個真正的幫助,因爲您的WebService客戶端仍分別執行這兩種方法,因此登陸兩個不同的事務。

簡單的解決辦法是:

  • 使用數據庫(在SLSB無狀態),其可以與你的EJB事務同步,
  • 執行兩者的事務內的這些方法(例如incrementAndGet(-)方法對於WebService客戶端)。

比你可以相當肯定你得到的結果是一致的。

+0

謝謝,有兩件事,你的回答否定了洛佩茲的回答。對? 2,爲什麼StatelessEJB有一個狀態,如果有一個CountManager的變量。狀態實際上是在數據庫中。不是嗎? – anergy

+0

不,我不認爲它否定了奧斯卡的回答,因爲他還談到交易和數據庫的重要性,並參與交易。 –

+0

是的,你是對的 - 我沒有仔細閱讀你的POJO訪問數據庫,並假定它在CountManager中保持狀態。沒有依賴注入的POJO是很好的(至少如果你在構造函數中實例化它)。問題是 - 你如何訪問數據庫,如果這個訪問是EJB事務感知。 –

2

注意,這不是真正的同步或多線程問題,而是事務行爲的問題。

上面的代碼如果在EJB中運行,將通過將事務支持委託給數據庫來處理競爭條件。根據隔離級別和事務屬性,數據庫可以負責鎖定底層表,以確保信息保持一致,即使面臨併發訪問和/或修改。