diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java index 1b1f474ce4a..266920c2f4b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java @@ -28,10 +28,10 @@ import java.nio.charset.StandardCharsets; import java.security.CodeSource; import java.util.Enumeration; -import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -58,7 +58,7 @@ public final class Version { public static final int LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT = 2000200; // 2.0.2 public static final int HIGHEST_PROTOCOL_VERSION = 2009900; // 2.0.99 - private static final Map VERSION2INT = new HashMap<>(); + private static final Map VERSION2INT = new ConcurrentHashMap<>(); static { // get dubbo version and last commit id diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java index 0c37dc79c77..a6e45766adc 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java @@ -24,6 +24,8 @@ import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.Enumeration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -98,6 +100,42 @@ void testIsFramework263OrHigher() { Assertions.assertTrue(Version.isRelease263OrHigher("2.6.3.0")); } + @Test + void testGetIntVersionConcurrency() throws InterruptedException { + int threadCount = 10; + int iterations = 1000; + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(threadCount); + AtomicInteger errors = new AtomicInteger(0); + + String[] versions = {"2.6.1", "2.7.0", "3.0.0", "2.0.2", "2.0.99", "3.1.0", "2.6.3.1", "2.7.0.RC1"}; + int[] expected = {2060100, 2070000, 3000000, 2000200, 2009900, 3010000, 2060301, 2070000}; + + for (int t = 0; t < threadCount; t++) { + new Thread(() -> { + try { + startLatch.await(); + for (int i = 0; i < iterations; i++) { + int idx = i % versions.length; + int result = Version.getIntVersion(versions[idx]); + if (result != expected[idx]) { + errors.incrementAndGet(); + } + } + } catch (Exception e) { + errors.incrementAndGet(); + } finally { + doneLatch.countDown(); + } + }) + .start(); + } + + startLatch.countDown(); + doneLatch.await(); + Assertions.assertEquals(0, errors.get(), "Concurrent getIntVersion should return consistent results"); + } + @Test void testGetVersion() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {