需要简单的解释“锁条带化”如何使用 ConcurrentHashMap

根据Java并发实践,第11.4.3章说:

锁拆分有时可以扩展到对一组可变大小的独立对象进行分区锁定,在这种情况下,它被称为锁条带化。例如,ConcurrentHashMap的实现使用16个锁的数组,每个锁保护1/16的哈希桶;桶 N 由锁 N mod 16 保护。

我仍然有问题来理解和可视化锁条带化和桶机制。有人可以用很好的理解的话来解释这一点:)

提前致谢。


答案 1

哈希映射基于数组构建,其中哈希函数将对象映射到基础数组中的元素。假设底层数组有 1024 个元素 - ConcurrentHashMap 实际上将其转换为 64 个元素的 16 个不同的子数组,例如 {0, 63}, {64, 127} 等。每个子数组都有自己的锁,因此修改 {0, 63} 子数组不会影响 {64, 127} 子数组 - 一个线程可以写入第一个子数组,而另一个线程可以写入第二个子数组。


答案 2

锁定 a 和 a 之间的区别如下:Collections.synchronizedMap()ConcurrentHashMap

如果多个线程将频繁访问一个,则会出现很多争用,因为每个方法都是使用共享锁同步的(即,如果线程 X 调用 a 上的方法,则所有其他线程将被阻止调用 a 上的任何方法,直到线程 X 从它调用的方法返回)。Collections.synchronizedMap()Collections.synchronizedMap()Collections.synchronizedMap()

A 具有可变数量的锁(缺省值为 16 个),每个锁保护 中的一段键。因此,对于拥有160把钥匙的a,每把锁将保护10个元素。因此,对密钥(、 、 等) 操作的方法仅锁定对密钥位于同一段中的密钥上操作的其他方法的访问。例如,如果线程 X 调用 ,然后线程 Y 调用,则这些调用可以并发执行,并且线程 Y 不必等待线程 X 从 返回。下面提供了一个示例。ConcurrentHashMapConcurrentHashMapConcurrentHashMapgetputsetput(0, someObject)put(10, someOtherObject)put(0, someObject)

此外,某些方法(如 和)根本不受保护。虽然这允许更高的并发性,但这意味着它们不是强一致性(它们不会反映并发变化的状态)。size()isEmpty()

public static void main(String[] args) {
  ConcurrentHashMap<Integer, Object> map = new ConcurrentHashMap<>(160);

  new Thread(new Runnable() {
    @Override
    public void run() {
      map.put(0, "guarded by one lock");
    }
  }.start();

  new Thread(new Runnable() {
    @Override
    public void run() {
      map.put(10, "guarded by another lock");
    }
  }.start();

  new Thread(new Runnable() {
    @Override
    public void run() {
      // could print 0, 1, or 2
      System.out.println(map.count());
    }
  }.start();
}

推荐