ConcurrentHashMap:每个键仅调用一种方法

每种方法ConcurrentHashMap都是线程安全的。但是,从ConcurrentHashMap同一键调用多个方法会导致争用条件。从ConcurrentHashMap不同的键递归调用相同的方法会导致死锁。

 

让我们看一个例子,看看为什么会发生这种情况:

 

调用多个方法

 

在下面的测试中,我ConcurrentHashMap对相同的键1 使用了from的两个方法。第update3行到第10行的方法   首先从ConcurrentHashMap using方法   获取值   get。比update增加值,并使用方法put 第6行和第8行将其放回   :

ConcurrentHashMap:每个键仅调用一种方法

ConcurrentHashMap:每个键仅调用一种方法

ConcurrentHashMap:每个键仅调用一种方法

为了测试会发生什么,我使用在第18和21行中创建的两个线程。我在第25和25行中启动了这两个线程。然后等待,直到在26和27行中使用线程连接都结束了。在两个线程都停止之后我检查第28行的值是否确实为2。

 

为了测试所有线程交织,我们将完整的测试放在while循环中,使用AllInterleavings 来自vmlens的类(第15行)遍历所有线程交织   。运行测试,我看到以下错误:

ConcurrentHashMap:每个键仅调用一种方法

要查看为什么结果是一个而不是预期的两个,我们可以查看生成的报告vmlens:

ConcurrentHashMap:每个键仅调用一种方法

所以。问题是首先两个线程都调用get,,然后两个线程都调用put。因此,两个线程都看到一个空值,并将该值更新为1。这导致结果为一,而不是预期的二。解决此竞争条件的技巧是仅使用一种方法而不是两种方法来更新值。使用方法compute我们可以做到这一点。因此,正确的版本如下所示:

ConcurrentHashMap:每个键仅调用一种方法

递归调用相同的方法

 

现在,让我们来看一个从ConcurrentHashMap递归调用相同方法的示例:

ConcurrentHashMap:每个键仅调用一种方法

在这里,我们为不同的键调用compute方法内部的compute方法。一次输入**,然后输入两个,一次输入**,然后输入两个。如果运行测试,则会看到以下死锁:

ConcurrentHashMap:每个键仅调用一种方法

要了解为什么会发生这种僵局,我们必须查看的内部ConcurrentHashMapConcurrentHashMap使用数组存储键和值之间的映射。每次我们更新的映射时,ConcurrentHashMap,它都会锁定存储该映射的数组元素。因此,在我们的测试中,对**一进行计算的调用锁定了**一的数组元素。然后,我们尝试锁定键2的数组元素。但是此**已经被另一个线程锁定,该线程为**2调用compute,并尝试锁定**1的数组元素。僵局。

 

请注意,只有更新才需要锁定数组元素。只读方法(例如)get不使用锁。因此,getcompute调用内使用方法是没有问题的。

 

结论

 

使用ConcurrentHashMap一个线程安全的方式是很容易。选择一种最适合你需要的方法,然后每个键只使用一次

 

有什么问题可以加下qq:2062583349。也可添加vx:admindesire,有java、python、web等习资料和视频课程干货”。欢迎交流!