简体   繁体   English

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

[英]Need simple explanation how “lock striping” works with ConcurrentHashMap

According to Java Concurrency in Practice, chapter 11.4.3 says: 根据Java Concurrency in Practice,第11.4.3章说:

Lock splitting can sometimes be extended to partition locking on a variablesized set of independent objects, in which case it is called lock striping. 锁分裂有时可以扩展到一组变量独立对象的分区锁定,在这种情况下,它被称为锁定条带。 For example, the implementation of ConcurrentHashMap uses an array of 16 locks, each of which guards 1/16 of the hash buckets; 例如,ConcurrentHashMap的实现使用一个包含16个锁的数组,每个锁保护1/16的散列桶; bucket N is guarded by lock N mod 16. 铲斗N由锁定N mod 16保护。

I still have problems to understand and visualize the lock striping and buckets mechanism. 我仍然有理解和可视化锁条纹和铲斗机制的问题。 Can someone explain this with good understanding words :) 有人可以用很好理解的话来解释这个:)

Thanks in advance. 提前致谢。

The hash map is built on an array, where the hash function maps an object to an element in the underlying array. 哈希映射构建在数组上,其中哈希函数将对象映射到基础数组中的元素。 Let's say the underlying array has 1024 elements - ConcurrentHashMap actually turns this into 16 different sub-arrays of 64 elements, eg {0, 63}, {64, 127}, etc. Each sub-array has its own lock, so modifying the {0, 63} sub-array doesn't impact the {64, 127} sub-array - one thread can write to the first sub-array while another thread writes to the second sub-array. 假设底层数组有1024个元素 - ConcurrentHashMap实际上将其转换为16个不同的64个元素的子数组,例如{0,63},{64,127}等。每个子数组都有自己的锁,所以修改{0,63}子数组不影响{64,127}子数组 - 一个线程可以写入第一个子数组,而另一个线程写入第二个子数组。

The difference between locking in a Collections.synchronizedMap() and a ConcurrentHashMap is as follows: 锁定Collections.synchronizedMap()ConcurrentHashMap之间的区别如下:

If multiple threads will access a Collections.synchronizedMap() frequently, there will be a lot of contention since each method is synchronized using a shared lock (ie if thread X calls a method on a Collections.synchronizedMap() , all other threads will be blocked from calling any method on a Collections.synchronizedMap() until thread X returns from the method it called). 如果多个线程经常访问Collections.synchronizedMap() ,则会有很多争用,因为每个方法都使用共享锁进行同步(即,如果线程X调用Collections.synchronizedMap()上的方法,则所有其他线程将是阻止调用Collections.synchronizedMap()上的任何方法,直到线程X从它调用的方法返回为止。

A ConcurrentHashMap has a variable number of locks (default is 16) that each guard a segment of the keys in the ConcurrentHashMap . ConcurrentHashMap具有可变数量的锁(默认值为16),每个锁都保护ConcurrentHashMap的一段键。 So for a ConcurrentHashMap with 160 keys, each lock will guard 10 elements. 因此对于具有160个键的ConcurrentHashMap ,每个锁将保护10个元素。 Therefore, methods operating on a key ( get , put , set , etc...) only lock out access to other methods operating on a key where the keys are in the same segment. 因此,对密钥( getputset等)进行操作的方法仅锁定对在密钥位于同一段中的密钥上操作的其他方法的访问。 For example, if thread X calls put(0, someObject) , and then thread Y calls put(10, someOtherObject) those calls can execute concurrently, and thread Y does not have to wait for thread X to return from put(0, someObject) . 例如,如果线程X调用put(0, someObject) ,然后线程Y调用put(10, someOtherObject)那些调用可以并发执行,并且线程Y不必等待线程X从put(0, someObject)返回put(0, someObject) An example is provided below. 下面提供一个例子。

Additionally, certain methods such as size() and isEmpty() are not guarded at all. 此外,某些方法(如size()isEmpty()根本不受保护。 While this allows for greater concurrency, it means they are not strongly-consistent (they won't reflect state that is concurrently changing). 虽然这允许更大的并发性,但这意味着它们不是非常一致的(它们不会反映同时发生变化的状态)。

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();
}

The key concept here is the "bucket" . 这里的关键概念是“桶”。 instead using a global lock for this whole hash Table, it uses one small lock for each bucket. 相反,对整个哈希表使用全局锁,它为每个桶使用一个小锁。 It's also a good analogous to bucket sort which can improve sorting complexity. 它也类似于桶排序,可以提高排序复杂性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM