2012-06-20 41 views
14

什麼是防止一個記錄的同步更新在不鎖定整個集合設置一個關鍵值的最佳方式的鎖?在語義上,我用鑰匙尋找某種鎖定的(理想情況下,Java實現,但不一定):如何獲得通過的關鍵

interface LockByKey { 
    void lock(String key); // acquire an exclusive lock for a key 
    void unlock(String key); // release lock for a key 
} 

這種鎖是爲了同步到遠程存儲的訪問,所以一些同步的Java集合不是一種選擇。

+1

這與您如何同步訪問遠程存儲有很大關係。不知道是否可以在不知道如何遠程管理併發性的情況下回答此問題。 –

+0

看看http://stackoverflow.com/a/28347825/704335。 – Timmos

+0

您可以使用:http://stackoverflow.com/a/28723518/1183010 –

回答

25

番石榴有這樣的東西被釋放在13.0;如果你喜歡,你可以把它從頭部取出。

Striped<Lock>或多或少分配鎖的具體數量,然後分配字符串基於其散列碼鎖。該API看起來或多或少像

Striped<Lock> locks = Striped.lock(stripes); 
Lock l = locks.get(string); 
l.lock(); 
try { 
    // do stuff 
} finally { 
    l.unlock(); 
} 

更多或更少的,條紋的數量可控,您可以併發交易對內存的使用,因爲分配完全鎖閉每個字符串鍵可以得到昂貴;從本質上講,當你得到散列衝突時,你只會得到鎖爭用,這可能是(可以預料的)罕見的。

(披露:我貢獻番石榴。)

+0

是否與舊鎖相關的內存得到清理?就像他們如果保存在WeakHashMap中一樣。 –

+2

如果使用工廠方法生成弱鎖,它會執行此操作。 –

+1

@Jose Martinez:不,它不需要清理任何東西,它不必遵循不同的原則。以「Striped.lock(1024)」爲例,它創建了一個簡單的Lock [1024]數組,用1024個預先生成的Lock對象進行了熱切初始化;請參閱「Striped.CompactStriped」。您可以擁有數十億個唯一ID的應用程序,但您的鎖池在1024處始終保持相同的鎖定。 「條帶化」操作的概率非常低,爲2或更多,生成相同散列的ID嘗試同時訪問互斥鎖。 – Espinosa

0

保持每桶互斥/鎖。這將確保只有衝突等待在該互斥體上。

0

如果「記錄」你提的是一個可變的對象,「更新」是指該對象的內部狀態,而不會干擾容器的結構,那麼你就可以完成你想要的只是通過鎖定記錄對象修改。

然而,如果「更新」是指從容器中取出的記錄對象和替換它,那麼你必須鎖定,則整個容器,以防止其他線程看到它處於不一致的狀態。

在這兩種情況下,你應該尋找在java.util.concurrent包中的類。

1

這就是這樣;我做的。是的,我同意如果兩個不同的字符串共享相同的哈希碼將最終獲得相同的鎖。

class LockByKey { 
    ObjectForString objHolder = new ObjectForString(100); 
    public void lockThenWorkForKey (String key) { 
     synchronized(objHolder.valueOf(key)){ 
      //DoSomeWork 
     } 
    } 
} 

public final class ObjectForString { 

    private final Object[] cache; 
    private final int cacheSize; 
    final int mask; 

    public ObjectForString(int size) { 
     // Find power-of-two sizes best matching arguments 
     int ssize = 1; 
     while (ssize < size) { 
      ssize <<= 1; 
     } 

     mask = ssize - 1; 
     cache = new Object[ssize]; 
     cacheSize = ssize; 
     //build the Cache 
     for (int i = 0; i < cacheSize; i++) { 
      this.cache[i] = new Object(); 
     } 
    } 

    public Object valueOf(String key) { 
     int index = key.hashCode(); 
     return cache[index & mask]; 
    } 
}