【问题标题】:Java synchronized method around parameter value围绕参数值的Java同步方法
【发布时间】:2016-09-14 12:50:02
【问题描述】:

考虑以下方法:

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

我想保护这个方法免受竞争条件的影响,但这只有在具有相同customerId 的两个线程同时调用它时才会发生。如果我制作整个方法synchronized,它会降低效率,而且它并不是真正需要的。我真正想要的是围绕customerId 同步它。这对Java有可能吗?是否有任何内置工具,或者我需要MapIntegers 来用作锁?

如果您认为我在这里做错了什么,也可以随时提出建议:)

谢谢!

【问题讨论】:

  • 确实感觉错了。也许您应该编辑您的问题,以提供更多关于为什么首先需要同步的详细信息。
  • upsert 听起来像是在执行一些数据库 dml。在这种情况下,您可能正在尝试通过锁定解决事务隔离问题?如果是这样,那将是一个坏主意。
  • @NathanHughes 我正在使用旧版本的 Postgres,其中 upsert 尚不可用 :)
  • 也许我没有抓住重点,但你为什么不在 JDBC 事务中做这件事,让 DBMS 为你处理锁定?

标签: java concurrency synchronized


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:
        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 不仅可以是“整数”,还可以是任何具有正确覆盖的“equals”和“hashCode”方法的类。
    • try-finally - 非常重要 - 即使您的操作抛出异常,您也必须保证在操作后解锁等待线程。
    • 如果您的后端分布在多个服务器/JVM上,它将无法工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-16
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多