2012-02-01 51 views
2

我寫了一個數據庫連接池,用於大型多線程應用程序,寫入目標jdk4標準,使用下面的代碼我可以在0.4秒內通過我的測試用例在局域網上查詢一個MySQL數據庫1000次。爲什麼這個鎖更改會影響JDBC的性能?

synchronized(lockA) { 
    if(free.size() > 0) { 
     c = (Connection) free.removeFirst(); 
    } 

    if(c == null) { 
     c = DriverManager.getConnection(query, name, passw); 
    } 
} 

這裏lockA保護空閒列表(LinkedList),它用於列表被修改和訪問的地方。把getConnection從這個鎖中移出並保存到它自己的保護塊中是有意義的。 getConnection需要被鎖保護,因爲它不是線程安全的。

所以,如果我改變它,所以DriverManager和列表受到單獨的鎖保護,就像這樣。

synchronized(lockA) { 
    if(free.size() > 0) { 
     c = (Connection) free.removeFirst(); 
    } 
} 

if(c == null) { 
    synchronized(lockB) { 
     c = DriverManager.getConnection(query, name, passw); 
    } 
} 

我得到持續的高速緩存未命中(C爲空)等性能降低,使得它需要4秒鐘做歷時0.4秒相同的查詢。

爲什麼會出現這種情況?

編輯:

我已經解決了這一點,問題就出現了從創建太多連接時功能塊的方式。

這就是在函數開始時發生的事情。

synchronized(waitLocK) { 
    try { 
     while(count >= limit) { 
      waitLock.wait(); 
     } 
    } catch (InterruptedException e) { 
    } 
} 

當連接被釋放時waitLock被釋放。但是這裏發生的是,在創建連接的代碼塊之後,計數變量(volatile)會增加。

這具有打開門的效果,因爲當1000個線程試圖通過等待測試時,他們都通過了,因爲count仍然爲0,然後重載了getConnection()。

移動count ++爲try後解決此問題。

+0

c是一個全局變量嗎? – Tudor 2012-02-01 10:29:39

+0

對不起,C是本地功能。 – FEiN 2012-02-01 10:35:35

+3

「我正在寫一個數據庫連接池」......這是什麼?有幾種可以使用的開源軟件。這是一個難以解決的問題,不要重新發明輪子。 – skaffman 2012-02-01 10:38:36

回答

0

代碼的第二種形式允許無限數量的線程同時請求與數據庫的連接,其中第一個線程一次只允許一個線程請求新的連接。

當用Java編寫併發代碼,我有一個簡單的規則:

如果你的代碼有synchronized關鍵字的話,它可能是錯誤的,並且會發生細微的和不可預測的方式失敗。

除了開玩笑,你需要長時間思考,爲什麼你不能用標準併發類來實現你想要的併發結果。

skaffman的評論是正確的 - 你真的不想實現連接池。選擇任何一種可用的實現。

假設這不是連接池,但是。爲什麼使用同步+ LinkedList而不是ConcurrentLinkedQueue?您的邏輯嘗試從列表中獲取連接;如果沒有連接可用,它會創建一個新的連接(這可能會導致調用者在完成連接後返回列表)。

Java Concurrency In Practice是一本很棒的書,如果你還沒有讀過它。

相關問題