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

Ged*_*bel 23 java concurrency concurrenthashmap java.util.concurrent

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

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

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

提前致谢.

Zim*_*oot 47

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

  • 然后它首先服务 - 第一个获取锁的线程进行更改,然后当它完成第二个线程进行更改时.`ConcurrentHashMap`有像'replace`这样的方法,以确保第二个线程不会无意中覆盖第一个线程的更改. (4认同)
  • 对 Java 8 实现进行了非常简要的了解,但我没有看到任何段级数组。我知道上面的答案是在 java 8 之前写的。但是现在有人可以澄清段只是表中的单个桶或行吗?因为我们不为行的条纹做锁,所以单词 lock striping 已经过时了吗? (2认同)

小智 15

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

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

A ConcurrentHashMap具有可变数量的锁(默认值为16),每个锁保护锁中的一段键ConcurrentHashMap.因此对于ConcurrentHashMap160键,每个锁将保护10个元素.因此,操作方法上的一个键(get,put,set等...)仅锁定访问上,其中键是在相同的段的一个关键操作的其它方法.例如,如果线程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();
}
Run Code Online (Sandbox Code Playgroud)