执行“规范”锁定对象

时间:2011-09-19 02:36:10

标签: java synchronization

我有一个数据对象存储,我希望一次同步与一个特定对象相关的修改。

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)在内存安全中方式?

3 个答案:

答案 0 :(得分:3)

将锁直接添加到此DataObject,您可以这样定义:

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 :(得分:1)

  

另一个想法是同步数据对象本身;但是,如果您有一个数据对象尚不存在的操作怎么办?例如,像addDataObject(DataObject)这样的方法会同步什么?

同步对象可能是可行的。

如果对象尚不存在,那么其他任何东西都无法看到它。如果您可以安排对象由其构造函数完全初始化,并且在构造函数返回之前它不是由构造函数发布的,那么您不需要同步它。另一种方法是在构造函数中部分初始化,然后使用synchronized方法执行构造和发布的其余部分。

答案 2 :(得分:1)

对于这种情况,我通常有2级锁定: 第一级作为读写器锁定,通过将其视为“写入”来确保对地图的更新(添加/删除)正确同步,并且对地图中的条目的访问在地图上被视为“已读”。一旦访问该值,然后同步该值。这是一个小例子:

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();
        }

    }
}

然后应该正确地同步所有内容而不会牺牲很多并发性