【问题标题】:Lock/Unlock based on value?根据价值锁定/解锁?
【发布时间】:2015-10-21 15:59:00
【问题描述】:

我有一个由 3 个并发线程在对象实例上调用的方法。我感兴趣的锁是基于值而不是对象。例如,如果两个线程 (T1,T2) 正在处理 RecordID=123,而 T3 正在处理 RecordID=456。该方法应该只锁定 T2 并且 T3 应该继续执行。

目前,我正在使用 Lock,但如果 T1 被锁定,它将同时锁定 T2 和 T3。

public void doSomething(String id){
      try {
       lock.lock();
       MyRecord r = find(id);
       ...
       ....
       } finally{
         lock.unlock();
       }
}

【问题讨论】:

标签: java multithreading synchronization thread-safety locking


【解决方案1】:

解决方案可能是基于哈希码实现分段锁定,类似于ConcurrentHashMap中的实现方式:

int concurrencyLevel = 1 << 8;   // 256 locks
final Lock[] locks = new Lock[concurrencyLevel];
// initialize locks

void doSomething(String id) {
    Lock lock = locks[id.hashCode() & (concurrencyLevel - 1)];  // select one of 256 locks 
    lock.lock();
    try {
        // do some work
    } finally {
        lock.release();
    }
}

相同的id 值始终具有相同的哈希码,因此它们将使用池中的相同锁。

【讨论】:

  • 那么1&lt;&lt;0也可以吗? :)
  • @bayou.io 当然,1 &lt;&lt; 0 只会使用一把锁
  • 不过要小心。通用锁可能会被占用较长时间,因此最好尽可能细化。
  • @bayou.io 的想法是在执行之前初始化所有锁,因此从数组中获取锁时不会发生竞争条件——它总是存在并且对于每个哈希码剩余部分总是一个。
  • 不要忘记 hashCode 可以返回负值。此外,上面的代码没有提供良好的分布。更安全的方法是:locks[Math.abs(id.hashCode()) % concurrencyLevel]
猜你喜欢
  • 2019-12-23
  • 2022-01-12
  • 2015-01-02
  • 1970-01-01
  • 2016-05-28
  • 2015-05-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多