From 0824f0d53b7931bf7a11391f7a47152e6d5e49a3 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Sun, 5 Jul 2026 11:49:28 +0000 Subject: [PATCH] fix #88: use CopyOnWriteArrayList for thread-safe message list - Change the messages list from ArrayList to CopyOnWriteArrayList - Add concurrency test for adding messages from multiple threads --- .../io/logging/DefaultMessageHolder.java | 4 ++-- .../io/logging/DefaultMessageHolderTest.java | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java b/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java index 765e0c1..e97fd7f 100644 --- a/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java +++ b/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java @@ -20,9 +20,9 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * Default Message Holder. @@ -30,7 +30,7 @@ */ public class DefaultMessageHolder implements MessageHolder { - private List messages = new ArrayList<>(); + private List messages = new CopyOnWriteArrayList<>(); private Message currentMessage; diff --git a/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java b/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java index 9186148..4827c3b 100644 --- a/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java +++ b/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java @@ -20,6 +20,11 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import org.junit.jupiter.api.Test; @@ -302,4 +307,21 @@ void appendCharSequence() { assertTrue(mh.render().contains("This is a test")); } + + @Test + void shouldAddMessagesConcurrently() throws Exception { + DefaultMessageHolder mh = new DefaultMessageHolder(); + ExecutorService executor = Executors.newFixedThreadPool(4); + List> futures = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + futures.add(executor.submit(() -> { + mh.addMessage("concurrent message"); + })); + } + for (Future future : futures) { + future.get(); + } + assertEquals(10, mh.size()); + executor.shutdown(); + } }