2011-09-19 72 views
3

我有一個數據對象的存儲區,我希望一次同步與某個特定對象相關的修改。「規範」鎖對象的實現

class DataStore { 
    Map<ID, DataObject> objects = // ... 
    // other indices and stuff... 

    public final void doSomethingToObject(ID id) { /* ... */ } 
    public final void doSomethingElseToObject(ID id) { /* ... */ } 
} 

也就是說,我不希望我的數據存儲擁有單個鎖,因爲對不同數據對象的修改是完全正交的。相反,我希望能夠僅鎖定與單個數據對象相關的鎖。

每個數據對象都有一個唯一的ID。一種方法是創建一個ID => Lock的地圖,並根據與該id關聯的一個鎖對象進行同步。另一種方法是做類似的事情:

synchronize(dataObject.getId().toString().intern()) { 
    // ... 
} 

但是,這看起來像是內存泄漏 - 內部化字符串可能永遠不會收集。

另一個想法是根據數據對象本身進行同步;然而,如果你有一個數據對象不存在的操作呢?例如,像addDataObject(DataObject)這樣的方法會同步什麼?

總之,我怎麼可以編寫一個函數f(s),其中sString,這樣f(s)==f(t)如果s.equals(t)在存儲安全的方式?

回答

1

對於這種情況,我通常有兩級鎖: 作爲讀寫器鎖的第一級,它確保更新到地圖(添加/刪除)通過將它們視爲「寫入」來正確同步,並且訪問地圖中的條目在地圖上被視爲「讀取」。一旦訪問該值,然後在該值上進行同步。這裏是一個小例子:

class DataStore { 
    Map<ID, DataObject> objMap = // ... 
    ReadWritLock objMapLock = new ReentrantReadWriteLock(); 
    // other indices and stuff... 
    public void addDataObject(DataObject obj) { 
     objMapLock.writeLock().lock(); 
     try { 
      // do what u need, u may synchronize on obj too, depends on situation 
      objMap.put(obj.getId(), obj); 
     } finally { 
      objMapLock.writeLock().unlock(); 
     } 
    } 

    public final void doSomethingToObject(ID id) { 
     objMapLock.readLock().lock(); 
     try { 
      DataObject dataObj = this.objMap.get(id); 
      synchronized(dataObj) { 
       // do what u need 
      } 
     } finally { 
      objMapLock.readLock().unlock(); 
     } 

    } 
} 

一切都應該再沒有犧牲太多的併發

+0

相當不錯,謝謝正確同步。 – Jake

3

直接添加鎖這個數據對象,你可以這樣定義它:使用時

public class DataObject { 
    private Lock lock = new ReentrantLock(); 

    public void lock() { this.lock.lock(); } 
    public void unlock() { this.lock.unlock(); } 
    public void doWithAction(DataObjectAction action) { 
    this.lock(); 
    try { 
     action.doWithLock(this) : 
    } finally { 
     this.unlock(); 
    } 
    } 

    // other methods here 

} 

public interface DataObjectAction { void doWithLock(DataObject object); } 

而且,你可以簡單地做這樣的:

DataObject object = // something here 
object.doWithAction(new DataObjectAction() { 

    public void doWithLock(DataObject object) { 
    object.setProperty("Setting the value inside a locked object"); 
    } 

}); 

有你有鎖定更改的單個對象。

如果在寫入過程中還發生讀取操作,您甚至可以將其設爲讀寫鎖定。

1

另一個想法是根據數據對象本身進行同步;然而,如果你有一個數據對象不存在的操作呢?例如,像addDataObject(DataObject)這樣的方法會同步什麼?

同步對象可能是可行的。

如果該對象尚不存在,那麼沒有其他人可以看到它。假設您可以安排該對象完全由其構造函數初始化,並且在構造函數返回之前它不由構造函數發佈,那麼您不需要同步它。另一種方法是在構造函數中部分初始化,然後使用同步方法來完成構造和發佈的其餘部分。