需要简单解释“锁定条带化”如何与ConcurrentHashMap一起使用

时间:2013-04-22 16:06:10

标签: java concurrency java.util.concurrent concurrenthashmap

根据Java Concurrency in Practice,第11.4.3章说:

  

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

我仍然有理解和可视化锁定条带和铲斗机制的问题。 有人可以用很好的理解来解释这个词:)

提前致谢。

3 个答案:

答案 0 :(得分:43)

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

答案 1 :(得分:15)

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

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

ConcurrentHashMap具有可变数量的锁(默认值为16),每个锁保护ConcurrentHashMap中的一段键。因此对于具有160个键的ConcurrentHashMap,每个锁将保护10个元素。因此,对密钥(getputset等等进行操作的方法只能锁定对密钥位于同一网段的密钥上运行的其他方法的访问权限。例如,如果线程X调用put(0, someObject),然后线程Y调用put(10, someOtherObject),则这些调用可以并发执行,而线程Y不必等待线程X从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();
}

答案 2 :(得分:3)

这里的关键概念是“桶”。相反,对整个哈希表使用全局锁,它为每个桶使用一个小锁。 它也类似于桶排序,可以提高排序复杂性。