2010-05-04 96 views
2

假設我有一個方法名爲doSomething(),我想在多線程應用程序中使用此方法(每個servlet都繼承自HttpServlet)。我想知道是否有可能競態條件會發生以下情況:jsp/servlets應用程序中的java方法和競爭條件

  1. doSomething()不staic方法,它的數據庫寫入值。
  2. doSomething()靜態方法,但它不會將值寫入數據庫。

我注意到我的應用程序中的很多方法可能導致競爭條件或髒讀/寫。例如,我有一個投票系統,並且對於每個投票操作,一定的方法將改變的單個單元格的值對於輪詢如下所示:

[poll_id |    poll_data  ] 
[1  | {choice_1 : 10, choice_2 : 20}] 

將JSP/Servlet的應用程序通過本身解決這些問題或者我必須自己解決所有這些問題?

謝謝..

回答

4

這取決於doSomething()的實現方式以及它的實際功能。我假設寫入數據庫使用JDBC連接,它們是而不是線程安全。這樣做的首選方法是創建ThreadLocal JDBC連接。

至於第二種情況,它取決於方法中發生了什麼。如果它不訪問任何共享的,可變的狀態,那就沒有問題。如果確實如此,那麼您可能需要適當地進行鎖定,這可能涉及將鎖添加到對這些變量的每個其他訪問中。

(注意,只是標記這些方法如​​不能解決任何併發錯誤。如果doSomething()遞增一個共享對象上的值,則所有訪問該變量需要被​​因爲i++不是一個原子操作。如果它就像增加一個計數器一樣簡單,你可以使用AtomicInteger.incrementAndGet()。)

+0

謝謝邁克。是的,我使用JDBC,我會讀到有關ThreadLocal的內容,再次感謝。 – Abdullah 2010-05-04 20:37:43

+1

Servlet API和其他JEE API簡化了這些。您的servlet方法中的本地變量實際上是線程本地的(在服務請求期間)。應用程序服務器中的JDBC連接池將爲每個線程提供自己的連接。大多數困難發生在不同的線程競爭,在這種情況下可能在數據庫本身。情緒表示,這是真正的設計工作開始的地方。 – djna 2010-05-04 20:54:33

0

我東西,你的問題的最佳解決方案是使用類似「同步」的關鍵字,並等待/通知!

+0

在servlets中這個appraoch很少是最好的解決方案。 – djna 2010-05-04 20:56:38

3

Servlet API當然不會奇蹟般地讓併發成爲非問題。

寫入數據庫時​​,它取決於持久層中的併發策略。悲觀鎖定,樂觀鎖定,最後贏家?當你「寫入數據庫」時,你需要決定如何處理,還有更多的事情要做。你是什​​麼意思想要當兩個人同時點擊按鈕時發生?

製作doSomething靜態似乎沒有太多的問題。那裏發生的是相關的部分。它是否修改靜態變量?那麼是的,可能會有競爭條件。

2

servlet api不會爲你做任何事情來讓你的併發問題消失。比如在你的servlets上使用synchronized關鍵字是一個壞主意,因爲你基本上迫使你的線程被一次處理一個,並且它破壞了你快速響應多個用戶的能力。

如果您使用Spring或EJB3,則任何一個都將提供線程本地數據庫連接以及指定事務的能力。你一定要看看其中的一個。

2

案例1中,您的servlet使用訪問數據庫的一些代碼。數據庫具有您應該利用的鎖定機制。造成這種情況的兩個重要原因是:數據庫本身可能會用於讀取和寫入數據的其他應用程序,但您的應用程序不足以應付與自身的競爭。並且:您自己的應用程序可能會部署到縮放的集羣Web容器,其中您的代碼的多個副本在不同的計算機上執行。

因此,處理數據庫中的鎖有許多標準模式,您可能需要閱讀悲觀和樂觀鎖定。

該servlet API和JBC連接池爲您提供了一些有用的保證,讓您可以在不使用Java同步提供了你的變量是方法範圍寫你的servlet代碼,在概念,你有

Start transaction (perhaps implicit, perhaps on entry to an ejb) 
    Get connection to DB (Gets you a connection from pool, associated with your tran) 
    read/write/update code 
    Close connection (actually keeps it for your thread until your transaction commits) 
    Commit (again maybe implictly) 

所以你唯一的真正的問題在於處理數據庫中的任何爭用。以上所有內容都傾向於使用諸如JPA這樣的事物來更好地完成,但是在這種情況下,或多或少發生了什麼。情況2:靜態方法,這大概意味着你現在把所有的東西放在一個內存結構中。這(禁止某種類型的遠程調用)會隱藏單個JVM,並且您管理自己的鎖定。如果您的JVM或機器崩潰,我想你會丟失你的數據。如果你關心你的數據,那麼使用數據庫可能會更好。或者,其他方法如何:servlet通過將消息寫入持久JMS隊列來簡單記錄「投票」。讓其他進程從隊列中提取投票並添加它們。您不會以這種方式立即向選民提供反饋,但是您可以將用戶的體驗與實際(在類似場景中)的相當複雜的處理分離開來。