【问题标题】:Synchronized on instance object在实例对象上同步
【发布时间】:2020-04-26 19:14:07
【问题描述】:

我有一个服务方法,它基本上是将记录插入数据库。我想要实现的是基于对象或其变量阻止一段代码。

我需要根据这个 id 阻塞其他线程:rcvTransactionRequest.getPoDistributionId() 我不想阻止所有进入此方法的线程。最后,我正在尝试验证如果多个线程进入关键部分可能会发生的不应超过的应收数量。

    PoDistPayload poDistPayload = poDistService.getPoDist(rcvTransactionRequest.getPoDistributionId());
    synchronized (poDistPayload) {
        if (!poDistService.isReceivable(poDistPayload, rcvTransactionRequest.getQuantity()))
            throw ebsExceptionFactory.build(1036L, rcvTransactionRequest.getQuantity(), poDistPayload.getReceivableQuantity());

        PoDistRcv poDistRcv = PoDistRcv.of(rcvTransactionRequest);
        poDistRcv.setStatus(Status.TRANSACTION_STARTED);
        poDistRcv = poDistRcvRepository.save(poDistRcv);
        return new BaseTransactionResponse(poDistRcv.getTransactionId(), serialCountPerRequest, poDistRcv.getStatus());
    }

【问题讨论】:

  • 您是否希望根据distributionId 的值只允许一个线程进入临界区。不是对象实例?
  • 基本上是的,但我认为这无关紧要,因为该对象还有用于 equals 和 hashcode 的 distributionId 字段。

标签: java multithreading synchronized


【解决方案1】:

您可以使用 ConcurrentMap 来实现一个简单的锁定方案:

Object newLock=new Object();
Object existingLock;
// Wait until this thread can acquire lock
synchronized(newLock) {
  do {
    existingLock=cMap.putIfAbsent(distributionId,newLock);
    if(existingLock!=null) {
        // Locked by another thread. You can fail immediately, or wait until the lock is released
        synchronized(existingLock) {
          // Need timeout here because lock holder may notify before we wait
          existingLock.wait(timeout);
       }
    }
  } while(existingLock!=null);
  // You have the lock
  // Do work
  // Unlock and notify
  cMap.remove(distributionId,newLock);
  newLock.notify();
}

【讨论】:

  • 感谢您的回复。我得到了这个想法,但我决定使用 Guava Strip,我猜想在这个解决方案中使用类似的逻辑。
【解决方案2】:

我用番石榴条解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-05
    • 2016-01-29
    相关资源
    最近更新 更多