围绕参数值的Java同步方法

时间:2016-09-14 12:50:03

标签: java concurrency synchronized

考虑以下方法:

public void upsert(int customerId, int somethingElse) {
  // some code which is prone to race conditions    
}

我想保护此方法不受竞争条件的影响,但只有当两个具有相同customerId的线程同时调用它时才会发生这种情况。如果我制作整个方法synchronized,它将降低效率并且不是真正需要的。我真正想要的是在customerId周围进行同步。这有可能以某种方式与Java?是否有任何内置工具,或者我需要Map Integers作为锁使用?

如果您认为我在这里做错了,请随时提出建议:)

谢谢!

2 个答案:

答案 0 :(得分:11)

您正在寻找的概念称为分段锁定条带锁定。为每个客户设置一个单独的锁是非常浪费的(锁是非常重量级的)。相反,您希望将客户ID空间分区分成合理数量的分区,以匹配所需的并行度。通常8-16就足够了,但这取决于该方法的工作量。

这概述了一种简单的方法:

private final Object[] locks = new Object[8];

synchronized (locks[customerId % locks.length]) {
    ...implementation...
}

答案 1 :(得分:0)

    private static final Set<Integer> lockedIds = new HashSet<>();

    private void lock(Integer id) throws InterruptedException {
        synchronized (lockedIds) {
            while (!lockedIds.add(id)) {
                lockedIds.wait();
            }
        }
    }

    private void unlock(Integer id) {
        synchronized (lockedIds) {
            lockedIds.remove(id);
            lockedIds.notifyAll();
        }
    }

    public void upsert(int customerId) throws InterruptedException {
        try {
            lock(customerId);

            //Put your code here.
            //For different ids it is executed in parallel.
            //For equal ids it is executed synchronously.

        } finally {
            unlock(customerId);
        }
    }
  • id 不仅可以是'Integer',而且可以是具有正确覆盖的'equals'和'hashCode'方法的任何类。
  • 最终尝试-非常重要-即使操作引发异常,您也必须保证在操作后解锁等待线程。
  • 如果您的后端分布在多个服务器/ JVM 中,则将无法使用。