我希望有一些机制,允许我根据equals()实现获取每个对象的锁。
我在寻找现有的解决方案。我发现番石榴去掉了,但问题是我无法保证对于不同的equals()值,我会得到不同的锁。
在我的场景中,这是一个问题,因为我需要获得两个锁,第二个锁还在我持有第一个锁时,所以对不同的值使用相同的锁会导致死锁。
对于我想要达到的目标,有什么解决方案吗?单独实现这一点可能非常棘手,因此,这就是为什么我要考虑一些现有的和经过测试的解决方案。
编辑:当问题出现时,我会尝试解释得更多一些。我有某种事务,在这种事务中,我更新两个对象的状态。一旦启动了这个事务,我就不希望任何其他线程启动任何涉及这两个对象的事务,直到我完成已经启动的事务。但是,我希望能够启动涉及其他对象的任何其他事务。示例:
对象:A,A' (与A相同,不同实例),B,E 113CE 214
线程1:试图获得A和B的锁
Thread 2:试图获得A'和C的锁
预期结果:如果线程1启动了事务,线程2需要等待Thread 1完成它的事务(因为A和A‘E 236具有相同的equals()值)。
发布于 2018-06-11 10:50:33
不是严格使用equals,而是equals和hashCode (您应该一起重写它们),下面的问题是什么?
class LockFactory<T>
{
private final Map<T, Object> objectToLock = new HashMap<>();
synchronized Object getLock(T input)
{
objectToLock.putIfAbsent(input, new Object());
return objectToLock.get(input);
}
}您可以在Object上同步,或者返回某种类型的Lock (如果您愿意)。
发布于 2018-06-11 12:32:26
这是经过@Michael的一些思考和建议后我实现的解决方案。也许有人会发现它有用,或者在其中发现了一些错误:
public class LockedExecutionProvider {
private final HashMap<Long, LockWithUsageCount> locks = new HashMap<>();
public <T> T executeLocked(Supplier<T> supplier, Long... ids) {
List<Lock> idsLocks = asList(ids).stream().sorted().map(this::getLock).collect(Collectors.toList());
idsLocks.forEach(Lock::lock);
try {
return supplier.get();
} finally {
idsLocks.forEach(Lock::unlock);
asList(ids).forEach(this::returnLock);
}
}
private synchronized Lock getLock(Long id) {
LockWithUsageCount lockWithUsageCount = locks.computeIfAbsent(id, i -> new LockWithUsageCount());
lockWithUsageCount.incrementUsageCount();
return lockWithUsageCount.getLock();
}
private synchronized void returnLock(Long id) {
LockWithUsageCount lockWithUsageCount = locks.get(id);
if (0 == lockWithUsageCount.decrementUsageCount()) {
locks.remove(id);
}
}
private static final class LockWithUsageCount {
private final Lock lock;
private int usageCount;
LockWithUsageCount() {
this.lock = new ReentrantLock();
usageCount = 0;
}
Lock getLock() {
return lock;
}
void incrementUsageCount() {
usageCount++;
}
int decrementUsageCount() {
return --usageCount;
}
}
}https://stackoverflow.com/questions/50795895
复制相似问题