diff --git a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java index 8cd9fc8dc..f6f897829 100644 --- a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java +++ b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java @@ -2,10 +2,10 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import dev.openfeature.sdk.EvaluationContext; import dev.openfeature.sdk.EventProvider; @@ -44,7 +44,7 @@ public Metadata getMetadata() { } public InMemoryProvider(Map> flags) { - this.flags = new HashMap<>(flags); + this.flags = new ConcurrentHashMap<>(flags); } /** @@ -67,7 +67,7 @@ public void updateFlags(Map> flags) { Set flagsChanged = new HashSet<>(); flagsChanged.addAll(this.flags.keySet()); flagsChanged.addAll(flags.keySet()); - this.flags = new HashMap<>(flags); + this.flags = new ConcurrentHashMap<>(flags); ProviderEventDetails details = ProviderEventDetails.builder() .flagsChanged(new ArrayList<>(flagsChanged)) .message("flags changed") diff --git a/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java b/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java index ffdc31822..58426c24b 100644 --- a/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java +++ b/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java @@ -14,6 +14,8 @@ import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import static dev.openfeature.sdk.Structure.mapToStructure; import static dev.openfeature.sdk.testutils.TestFlagsUtils.buildFlags; @@ -105,4 +107,23 @@ void shouldThrowIfNotInitialized() { // ErrorCode.PROVIDER_NOT_READY should be returned when evaluated via the client assertThrows(ProviderNotReadyError.class, ()-> inMemoryProvider.getBooleanEvaluation("fail_not_initialized", false, new ImmutableContext())); } + + @Test + void multithreadedTest() { + ExecutorService executorService = Executors.newFixedThreadPool(100); + for (int i = 0; i < 10000; i++) { + String flagKey = "multithreadedFlag" + i; + executorService.submit(() -> { + provider.updateFlag(flagKey, Flag.builder() + .variant("on", true) + .variant("off", false) + .defaultVariant("on") + .build()); + }); + } + + for (int i = 0; i < 10000; i++) { + assertTrue(client.getBooleanValue("multithreadedFlag" + i, false)); + } + } } \ No newline at end of file