2012-07-30 71 views
2

我的問題是關於在Java中鎖定對象實例。 我有以下方法,可以在同一時間由多個線程調用。我選擇鎖定一個對象實例,因爲我希望允許併發處理,只要一次只能由一個線程訪問一個實例。對對象實例的java鎖定...這是安全的嗎?

我的簡化代碼就像這樣,我基本上鎖定一個局部變量。 這真的會令我滿意嗎?我一直在閱讀的建議永遠不會鎖定一個可能會改變的對象,我突然不確定這是我究竟做了什麼!

謝謝!

編輯:

哦,親愛的...我只是意識到,我試圖簡化我的郵政代碼可能會有點誤導。

我將以前稱爲「getInstance」的方法重命名爲其他方法(「getFromMap」)以演示方法調用是自定義代碼,該代碼返回對散列表中對象的引用。

上一個答案仍然成立嗎?爲混淆道歉!

public boolean processInput(...) { 
if(message == 1) { 
    Class_0 context = (Class_0)Class_0.getFromMap("xyz"); 
    synchronized(context) { 
     context.setContextParams("abc"); 
     context.evaluateContextRules(message, this); 
    } 
} else if(message == 2) { 
    Class_1 context = (Class_1)Class_1.getFromMap("efg"); 
    synchronized(context) { 
     context.setContextParams("abc"); 
     context.evaluateContextRules(message, this); 
    } 
} 
..... 
} 
+1

這看起來像一個代碼氣味,誠實。爲什麼'TestForInternals_0'有兩種不同的可能類型? – 2012-07-30 13:33:21

+0

我試圖簡化張貼的代碼,並把它弄得一團糟......道歉! – user1563047 2012-07-30 13:37:14

+0

好吧,我想我現在看到它......但這仍然有點臭。也許你可以使用'enum'作爲消息,並在枚舉方法中指定不同的行爲? – 2012-07-30 13:38:41

回答

1

假設:

Class_1 context = (Class_1)TestForInternals_0.getInstance("efg"); 

只是檢索到現有的對象的引用,並且不會創建一個新的實例,則該對象的監視器將被鎖定,你在做什麼是有效的。

3

對象類型的變量只是一個參考對象;這是鎖定的對象,而不是參考。如果且僅當所有可能讀取或寫入相關數據的客戶端都同意只有在鎖定同一對象時才這樣做,則此類鎖定纔有效。無論是否是局部變量都無關緊要 - 它是否每個人都使用與鎖相同的對象。

在這裏,你的物體似乎來自某種工廠;如果getInstance(X)總是返回給定值爲X的相同對象,那麼您可能是不錯的。

0

只要修改你做context不影響什麼將由getInstance方法返回

1

是不是真的有足夠的「背景」您的代碼就可以了(雙關語不打算)你的問題是當然,如果這段代碼完全是線程安全的。但是,如果我們假設1)message是一個局部變量,並且2)訪問或更新上下文對象的所有內容都是在同步對象時執行的,則此片段中的代碼是線程安全的。


我一直在閱讀的建議從來沒有鎖定對象可能會改變,我突然不能確定這是否是我在做什麼畢竟!

你應該擔心什麼是這樣的:

public class Foo { 
    // some state variables 

    public Object lock = new Object(); 

    public void doSomething(...) { 
     synchronized (lock) { 
      .... 
     } 
    } 
} 

這可能是不安全的。如果在恰當的時間改變了lock的值,並且同一個Foo實例上的兩個操作可能最終使用不同的鎖對象進行同步。這可能會導致涉及Foo狀態的操作不能正確同步。

在您的示例中,context上的同步似乎是針對上下文對象本身的操作,因此上述問題不適用。

0

據我所知,你的方法processInput被調用,你的synchonized塊確保context.evaluateContextRules(...)只在一個線程中運行。

如果這是您的目標,那麼是的,您的代碼就是這樣做的。

其他人提到你必須確保你鎖定了對象,而不是對象的引用。那麼,因爲它看起來在你的代碼中,你在同一個對象上同步你調用一個方法,所以這不應該是一個問題。