围绕参数值的Java同步方法

问题描述 投票:5回答:2

请考虑以下方法:

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

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

如果您认为我在这里做错了,请随时咨询:)

谢谢!

java concurrency synchronized
2个回答
12
投票

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

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

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

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

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'方法的类。
  • try-finally - 非常重要 - 即使您的操作引发异常,您也必须保证在操作后解锁等待的线程。
  • 如果您的后端分布在多个服务器/ JVM上,它将无法工作。
© www.soinside.com 2019 - 2024. All rights reserved.