You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2023/05/10 05:30:45 UTC
[dubbo] branch 3.2 updated: fix #11986 ConcurrentHashMapUtils lock bug (#11987)
This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.2
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.2 by this push:
new 0c11a0ddcf fix #11986 ConcurrentHashMapUtils lock bug (#11987)
0c11a0ddcf is described below
commit 0c11a0ddcfc607a1aa45ef2915479bc59f1e3e7d
Author: Golden Looly <lo...@aliyun.com>
AuthorDate: Wed May 10 13:30:36 2023 +0800
fix #11986 ConcurrentHashMapUtils lock bug (#11987)
* fix #11986
* fix apache#11986
* fix apache#11986
* change test at jdk8
* seprate test for jdk8 and jdk17
* seprate jre version test
* change comment to english
* add null check for v
---------
Co-authored-by: Albumen Kevin <jh...@gmail.com>
---
.../dubbo/common/utils/ConcurrentHashMapUtils.java | 18 +++++++++++++-
.../common/utils/ConcurrentHashMapUtilsTest.java | 29 ++++++++++++++++++++++
2 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtils.java
index 2574d10202..7e71a1bab0 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtils.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.common.utils;
+import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@@ -32,10 +33,25 @@ public class ConcurrentHashMapUtils {
*
*/
public static <K, V> V computeIfAbsent(ConcurrentMap<K, V> map, K key, Function<? super K, ? extends V> func) {
+ Objects.requireNonNull(func);
if (JRE.JAVA_8.isCurrentVersion()) {
V v = map.get(key);
if (null == v) {
- v = map.computeIfAbsent(key, func);
+ // issue#11986 lock bug
+ // v = map.computeIfAbsent(key, func);
+
+ // this bug fix methods maybe cause `func.apply` multiple calls.
+ v = func.apply(key);
+ if(null == v){
+ return null;
+ }
+ final V res = map.putIfAbsent(key, v);
+ if(null != res){
+ // if pre value present, means other thread put value already, and putIfAbsent not effect
+ // return exist value
+ return res;
+ }
+ // if pre value is null, means putIfAbsent effected, return current value
}
return v;
} else {
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtilsTest.java
index 3fc895497f..66c1ae462d 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtilsTest.java
@@ -18,10 +18,12 @@
package org.apache.dubbo.common.utils;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
import java.util.concurrent.ConcurrentHashMap;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
class ConcurrentHashMapUtilsTest {
@@ -37,4 +39,31 @@ class ConcurrentHashMapUtilsTest {
ifAbsent = ConcurrentHashMapUtils.computeIfAbsent(map, "mxsm", k -> "mxsm1");
assertEquals("mxsm1", ifAbsent);
}
+
+ @Test
+ @EnabledForJreRange(max = org.junit.jupiter.api.condition.JRE.JAVA_8)
+ public void issue11986ForJava8Test(){
+ // https://github.com/apache/dubbo/issues/11986
+ final ConcurrentHashMap<String,Integer> map=new ConcurrentHashMap<>();
+ // // map.computeIfAbsent("AaAa", key->map.computeIfAbsent("BBBB",key2->42));
+
+ // In JDK8,for the bug of JDK-8161372,may cause dead cycle when use computeIfAbsent
+ // ConcurrentHashMapUtils.computeIfAbsent method to resolve this bug
+ ConcurrentHashMapUtils.computeIfAbsent(map, "AaAa", key->map.computeIfAbsent("BBBB",key2->42));
+ assertEquals(2, map.size());
+ assertEquals(Integer.valueOf(42), map.get("AaAa"));
+ assertEquals(Integer.valueOf(42), map.get("BBBB"));
+ }
+
+ @Test
+ @EnabledForJreRange(min = org.junit.jupiter.api.condition.JRE.JAVA_9)
+ public void issue11986ForJava17Test(){
+ // https://github.com/apache/dubbo/issues/11986
+ final ConcurrentHashMap<String,Integer> map=new ConcurrentHashMap<>();
+
+ // JDK9+ has been resolved JDK-8161372 bug, when cause dead then throw IllegalStateException
+ assertThrows(IllegalStateException.class, ()->{
+ ConcurrentHashMapUtils.computeIfAbsent(map, "AaAa", key->map.computeIfAbsent("BBBB",key2->42));
+ });
+ }
}