|
@@ -36,12 +36,14 @@ import java.nio.charset.StandardCharsets;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Collection;
|
|
|
+import java.util.ConcurrentModificationException;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Random;
|
|
|
import java.util.Set;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
import java.util.regex.Pattern;
|
|
|
import static java.util.concurrent.TimeUnit.*;
|
|
|
|
|
@@ -2133,6 +2135,39 @@ public class TestConfiguration extends TestCase {
|
|
|
checkCDATA(os.toByteArray());
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ public void testConcurrentModificationDuringIteration() throws InterruptedException {
|
|
|
+ final Configuration configuration = new Configuration();
|
|
|
+ new Thread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ while (true) {
|
|
|
+ configuration.set(String.valueOf(Math.random()), String.valueOf(Math.random()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).start();
|
|
|
+
|
|
|
+ final AtomicBoolean exceptionOccurred = new AtomicBoolean(false);
|
|
|
+
|
|
|
+ new Thread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+ configuration.iterator();
|
|
|
+ } catch (final ConcurrentModificationException e) {
|
|
|
+ exceptionOccurred.set(true);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).start();
|
|
|
+
|
|
|
+ Thread.sleep(1000); //give enough time for threads to run
|
|
|
+
|
|
|
+ assertFalse("ConcurrentModificationException occurred", exceptionOccurred.get());
|
|
|
+ }
|
|
|
+
|
|
|
private static Configuration checkCDATA(byte[] bytes) {
|
|
|
Configuration conf = new Configuration(false);
|
|
|
conf.addResource(new ByteArrayInputStream(bytes));
|