2009-02-23 28 views
155

如果我有一個具有靜態方法的util類,它將調用Hibernate函數來完成基本的數據訪問。我想知道如果制定方法​​是確保線程安全的正確方法。同步靜態方法在Java中如何工作?

我希望這可以防止信息訪問到同一個數據庫實例。但是,現在我確定下面的代碼是否阻止getObjectById在被特定類調用時調用所有類。

public class Utils { 
    public static synchronized Object getObjectById (Class objclass, Long id) { 
      // call hibernate class 
     Session session = new Configuration().configure().buildSessionFactory().openSession(); 
     Object obj = session.load(objclass, id); 
     session.close(); 
     return obj; 
    } 

    // other static methods 
} 

回答

127

通過使用一個靜態方法同步鎖定,您將synchronize the class methods and attributes(而不是實例方法和屬性)

所以你的假設是:正確。

我想知道如果使方法同步是確保線程安全的正確方法。

不是真的。你應該讓這個工作做你的RDBMS。他們擅長這種東西。

通過同步對數據庫的訪問,您將獲得的唯一一件事就是讓您的應用程序非常慢。此外,在您發佈的代碼中,您每次都會構建一個Session Factory,這樣,您的應用程序將花費更多時間訪問數據庫,而不是執行實際工作。

試想以下情形:以插入不同的信息到表T的記錄X

客戶A和B的嘗試

你的方法你得到的唯一的事情是確保一個被稱爲之後,在數據庫中會發生這種情況,因爲RDBMS將阻止他們同時從A中插入一半信息並從B中插入一半信息。結果將是相同的,但速度只有5倍(或更多)。

也許最好看看Hibernate文檔中的"Transactions and Concurrency"一章。大多數情況下,您嘗試解決的問題已經得到解決,並且是一種更好的方法。

+1

非常有幫助的回答!謝謝!所以Hibernate通過「樂觀鎖定」來處理cnocurrency。那麼就根本不需要使用「同步」方法來解決任何數據訪問的併發問題?僅當數據未存儲在數據庫中時才使用「同步」方法? ..你使用它們嗎? – tomato 2009-02-24 00:32:08

16

靜態方法使用該類作爲鎖定對象,在您的示例中爲Utils.class。所以是的,這是可以的。

2

如果是與數據庫中的數據有關,爲什麼不利用數據庫隔離鎖定來實現?

+0

我沒有任何數據庫背景。現在我明白了!!感謝您指出! :) – tomato 2009-02-24 00:37:31

2

要回答你的問題,是的,它的確如此:你的​​方法一次不能被多個線程執行。

9

爲什麼你想強制只有一個線程可以在任何時候訪問數據庫?

這是數據庫驅動程序執行任何必要鎖定的工作,假設Connection一次僅由一個線程使用!

最有可能的,你的數據庫是完全能夠處理多個並行訪問

+0

我打賭它是/是一些交易問題的解決方法。也就是說,該解決方案並不能解決真正的問題 – 2009-02-23 20:37:49

+1

我不知道這一點....我想我必須手動執行此操作。感謝您指出! :) – tomato 2009-02-24 00:36:45

205

爲了更一般地解決這個問題......

請記住,在方法的使用synchronized其實只是速記(假設類SomeClass的):

synchronized static void foo() { 
    ... 
} 

相同

static void foo() { 
    synchronized(SomeClass.class) { 
     ... 
    } 
} 

synchronized void foo() { 
    ... 
} 

被與

相同
void foo() { 
    synchronized(this) { 
     ... 
    } 
} 

您可以使用任何對象作爲鎖。如果你想鎖定的靜態方法的子集,你可以

class SomeClass { 
    private static final Object LOCK_1 = new Object() {}; 
    private static final Object LOCK_2 = new Object() {}; 
    static void foo() { 
     synchronized(LOCK_1) {...} 
    } 
    static void fee() { 
     synchronized(LOCK_1) {...} 
    } 
    static void fie() { 
     synchronized(LOCK_2) {...} 
    } 
    static void fo() { 
     synchronized(LOCK_2) {...} 
    } 
} 

(對於非靜態方法,你想使鎖是非靜態字段)

13

static synchronized意味着持有鎖的類的Class對象 其中,作爲 ​​表示持有該類的對象本身的鎖。這意味着,如果您正在訪問線程中的非靜態同步方法(執行中),則仍然可以使用另一個線程訪問靜態同步方法。

因此,在任何時間點通過多個線程訪問兩種相同類型的方法(兩種靜態方法或兩種非靜態方法)是不可能的。