2013-08-20 23 views
0

我必須搜索一個對象:首先在BlockingQueue,如果它不存在,那麼我需要搜索一個ConcurrentHashMap並需要做一些操作。這需要是線程安全的。同步訪問兩個不同的對象

下面的代碼是否正確? ConcurrentHashMap上的同步是否按預期工作?

synchronized(blockingQueue){ 
    if(!blockingQueue.contains(element)) {   
     synchronized(concurrentHashMap) {  
      //do something 
     } 
    } 
} 
+0

這取決於其他線程正在做什麼。 – Val

回答

0

我會說這樣做,最好的辦法就是換這個邏輯AA獨立的公共函數中,它在一個共同的鎖同步(比如,你把此功能的實用程序類的實例)象下面這樣:

class MyUtil{ 

    public synchronized Object getMyObject(){  
     //if not in queue then get from map 
     //no need to put any lock on queue or map now 
    } 
} 
+0

根據書中的java併發性 public class ListHelper { public list list = Collections.synchronizedList(new ArrayList ()); .... public synchronized boolean putIfAbsent(E x){ boolean absent =!list.contains(x); (缺席)list.add(x); 返回缺席; } } }這段代碼不是線程安全的,我們需要鎖定列表本身。所以改爲使用像同步(列表){ //做事 } –

+0

你已經誤解了當前形勢的概念。書中所寫的是正確的。然而,書中的信息是,兩種不同的同步操作分別不能被視爲原子操作。要處理這個創建一個同步塊,並在一個關鍵部分內執行這兩個操作 – Saurabh

+0

而不是方法本身同步,我寧願使用自定義鎖作爲@Dariusz提到 – Rachel

0

你能解釋一下嗎?誰正在訪問這些對象blockingQueue和concurrentHashMap。有線程只讀取/只寫入他們?

也許你應該看看java.util.concurrent.locks.ReadWriteLock。

2

首先,像你的例子中的同步可能不會做你的期望。你將不得不檢查這兩個集合的實現,並檢查它們是否自己同步,而不是其他任何內部對象。

如果您需要像這樣同步訪問,我認爲使用同步集合是一個壞主意。顯然,你的關鍵部分比簡單的讀/寫操作更復雜。考慮使用自定義鎖操作,像這樣:

final Object lock = new Object(); 

public void addDataToHashMap(Object param, Object val) { 
    synchronized(lock) { 
    concurrentHashMap.put(param, val); 
    } 
} 

public void performComplexOperations() { 
    synchronized (lock) { 
    if (!blockingQueue.contains(element)) {   
     processSomeData(concurrentHashMap); 
    } 
    } 
} 
+0

我同意......創建自定義鎖更合適,而不是使用同步收藏本身 – Rachel

1

尚未包括在以前的答案,一個重要的澄清是,synchronized(concurrentHashMap)鎖定散列圖,和'同步(BlockingQueue的)將鎖定隊列,並且它們可以繼續在同一對象上未同步的某個其他線程中更新。

報價爲ConcurrentHashMap的javadoc的:

不過,儘管所有操作都是線程安全的,檢索操作並不意味着鎖定,並沒有對的方式,阻止鎖定整個表中的任何支持所有的出入口。

這將有助於瞭解//do something應該做些什麼來給出更好的答案。