2011-09-19 40 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)这样的方法会同步什么?

同步对象可能是可行的。

如果该对象尚不存在,那么没有其他人可以看到它。假设您可以安排该对象完全由其构造函数初始化,并且在构造函数返回之前它不由构造函数发布,那么您不需要同步它。另一种方法是在构造函数中部分初始化,然后使用同步方法来完成构造和发布的其余部分。