我有一个数据对象存储,我希望一次同步与一个特定对象相关的修改。
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)
,其中s
是String
,这样f(s)==f(t)
如果s.equals(t)
在内存安全中方式?
答案 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();
}
}
}
然后应该正确地同步所有内容而不会牺牲很多并发性