首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用单独的锁保证每个值的锁定

使用单独的锁保证每个值的锁定
EN

Stack Overflow用户
提问于 2018-06-11 10:42:22
回答 2查看 72关注 0票数 0

我希望有一些机制,允许我根据equals()实现获取每个对象的锁。

我在寻找现有的解决方案。我发现番石榴去掉了,但问题是我无法保证对于不同的equals()值,我会得到不同的锁。

在我的场景中,这是一个问题,因为我需要获得两个锁,第二个锁还在我持有第一个锁时,所以对不同的值使用相同的锁会导致死锁。

对于我想要达到的目标,有什么解决方案吗?单独实现这一点可能非常棘手,因此,这就是为什么我要考虑一些现有的和经过测试的解决方案。

编辑:当问题出现时,我会尝试解释得更多一些。我有某种事务,在这种事务中,我更新两个对象的状态。一旦启动了这个事务,我就不希望任何其他线程启动任何涉及这两个对象的事务,直到我完成已经启动的事务。但是,我希望能够启动涉及其他对象的任何其他事务。示例:

对象:AA' (与A相同,不同实例),BE 113CE 214

线程1:试图获得AB的锁

Thread 2:试图获得A'C的锁

预期结果:如果线程1启动了事务,线程2需要等待Thread 1完成它的事务(因为AA‘E 236具有相同的equals()值)。

EN

回答 2

Stack Overflow用户

发布于 2018-06-11 10:50:33

不是严格使用equals,而是equalshashCode (您应该一起重写它们),下面的问题是什么?

代码语言:javascript
复制
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 (如果您愿意)。

票数 1
EN

Stack Overflow用户

发布于 2018-06-11 12:32:26

这是经过@Michael的一些思考和建议后我实现的解决方案。也许有人会发现它有用,或者在其中发现了一些错误:

代码语言:javascript
复制
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;
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50795895

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档