[Fix] Fixed concurrent modification exception in SynchronizedCollections
This commit is contained in:
parent
af8ac81a18
commit
a0b24f74a5
|
@ -29,7 +29,7 @@ public class SynchronizedCollections {
|
|||
|
||||
SynchronizedMapOfLists(MapOfLists<T, U> m) {
|
||||
this.m = m;
|
||||
this.mutex = new Object();
|
||||
this.mutex = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -174,7 +174,7 @@ public class SynchronizedCollections {
|
|||
|
||||
SynchronizedMapOfMaps(MapOfMaps<T, U, V> m) {
|
||||
this.m = m;
|
||||
this.mutex = new Object();
|
||||
this.mutex = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -341,7 +341,7 @@ public class SynchronizedCollections {
|
|||
|
||||
public SynchronizedMapOfSets(MapOfSets<T, U> m) {
|
||||
this.m = m;
|
||||
this.mutex = new Object();
|
||||
this.mutex = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -507,35 +507,35 @@ public class SynchronizedCollections {
|
|||
|
||||
@Override
|
||||
public int size() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.contains(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.toArray(a);
|
||||
}
|
||||
}
|
||||
|
@ -547,70 +547,70 @@ public class SynchronizedCollections {
|
|||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.remove(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> coll) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.containsAll(coll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> coll) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.addAll(coll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> coll) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.removeAll(coll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> coll) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.retainAll(coll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
c.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super E> consumer) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
c.forEach(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super E> filter) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.removeIf(filter);
|
||||
}
|
||||
}
|
||||
|
@ -631,7 +631,7 @@ public class SynchronizedCollections {
|
|||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream s) throws IOException {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
s.defaultWriteObject();
|
||||
}
|
||||
}
|
||||
|
@ -650,63 +650,63 @@ public class SynchronizedCollections {
|
|||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.equals(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.set(index, element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
list.add(index, element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.indexOf(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return list.addAll(index, c);
|
||||
}
|
||||
}
|
||||
|
@ -723,21 +723,21 @@ public class SynchronizedCollections {
|
|||
|
||||
@Override
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
synchronized (mutex) {
|
||||
return new SynchronizedList<>(list.subList(fromIndex, toIndex), mutex);
|
||||
synchronized (this.mutex) {
|
||||
return new SynchronizedList<>(list.subList(fromIndex, toIndex), this.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<E> operator) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
list.replaceAll(operator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super E> c) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
list.sort(c);
|
||||
}
|
||||
}
|
||||
|
@ -753,14 +753,14 @@ public class SynchronizedCollections {
|
|||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.equals(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return c.hashCode();
|
||||
}
|
||||
}
|
||||
|
@ -777,42 +777,42 @@ public class SynchronizedCollections {
|
|||
|
||||
@Override
|
||||
public Comparator<? super E> comparator() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return ss.comparator();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> subSet(E fromElement, E toElement) {
|
||||
synchronized (mutex) {
|
||||
return new SynchronizedSortedSet<>(ss.subSet(fromElement, toElement), mutex);
|
||||
synchronized (this.mutex) {
|
||||
return new SynchronizedSortedSet<>(ss.subSet(fromElement, toElement), this.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> headSet(E toElement) {
|
||||
synchronized (mutex) {
|
||||
return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex);
|
||||
synchronized (this.mutex) {
|
||||
return new SynchronizedSortedSet<>(ss.headSet(toElement), this.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> tailSet(E fromElement) {
|
||||
synchronized (mutex) {
|
||||
return new SynchronizedSortedSet<>(ss.tailSet(fromElement), mutex);
|
||||
synchronized (this.mutex) {
|
||||
return new SynchronizedSortedSet<>(ss.tailSet(fromElement), this.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E first() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return ss.first();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E last() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return ss.last();
|
||||
}
|
||||
}
|
||||
|
@ -829,55 +829,55 @@ public class SynchronizedCollections {
|
|||
}
|
||||
|
||||
public int size() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.size();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.containsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.containsValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
public V get(Object key) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
public V put(K key, V value) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public V remove(Object key) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
m.putAll(map);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
m.clear();
|
||||
}
|
||||
}
|
||||
|
@ -887,25 +887,25 @@ public class SynchronizedCollections {
|
|||
private transient Collection<V> values;
|
||||
|
||||
public Set<K> keySet() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
if (keySet == null)
|
||||
keySet = new SynchronizedSet<>(m.keySet(), mutex);
|
||||
keySet = new SynchronizedSet<>(m.keySet(), this.mutex);
|
||||
return keySet;
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
if (entrySet == null)
|
||||
entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
|
||||
entrySet = new SynchronizedSet<>(m.entrySet(), this.mutex);
|
||||
return entrySet;
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<V> values() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
if (values == null)
|
||||
values = new SynchronizedCollection<>(m.values(), mutex);
|
||||
values = new SynchronizedCollection<>(m.values(), this.mutex);
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
@ -913,102 +913,102 @@ public class SynchronizedCollections {
|
|||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.equals(o);
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getOrDefault(Object k, V defaultValue) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.getOrDefault(k, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(BiConsumer<? super K, ? super V> action) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
m.forEach(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
m.replaceAll(function);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.putIfAbsent(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.remove(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replace(K key, V oldValue, V newValue) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.replace(key, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V replace(K key, V value) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.replace(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.computeIfAbsent(key, mappingFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.computeIfPresent(key, remappingFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.compute(key, remappingFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
return m.merge(key, value, remappingFunction);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream s) throws IOException {
|
||||
synchronized (mutex) {
|
||||
synchronized (this.mutex) {
|
||||
s.defaultWriteObject();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
package li.strolch.utils.collections;
|
||||
|
||||
import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfLists;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SynchronizedMapOfListsTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SynchronizedMapOfListsTest.class);
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.executorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldForEach() throws ExecutionException, InterruptedException {
|
||||
|
||||
MapOfLists<String, String> mapOfLists = buildMapOfLists();
|
||||
AtomicBoolean run = new AtomicBoolean(false);
|
||||
Callable<Boolean> addTask = () -> addToMap(mapOfLists, run);
|
||||
|
||||
Callable<Boolean> iterateTask = () -> {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
mapOfLists.forEach((s, list) -> list.forEach(s1 -> logger.info(s + " " + s1)));
|
||||
mapOfLists.getList("Resource").forEach(s1 -> logger.info(" " + s1));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
runTest(addTask, iterateTask, run);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIterate() throws ExecutionException, InterruptedException {
|
||||
|
||||
MapOfLists<String, String> mapOfLists = buildMapOfLists();
|
||||
AtomicBoolean run = new AtomicBoolean(false);
|
||||
Callable<Boolean> addTask = () -> addToMap(mapOfLists, run);
|
||||
Callable<Boolean> iterateTask = () -> {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
Set<String> types = mapOfLists.keySet();
|
||||
for (String type : types) {
|
||||
synchronized (mapOfLists) {
|
||||
for (String id : mapOfLists.getList(type)) {
|
||||
logger.info(type + " " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mapOfLists) {
|
||||
List<String> resources = mapOfLists.getList("Resource");
|
||||
for (String value : resources) {
|
||||
logger.info("Resource: value: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
runTest(addTask, iterateTask, run);
|
||||
}
|
||||
|
||||
private void runTest(Callable<Boolean> addTask, Callable<Boolean> iterateTask, AtomicBoolean run)
|
||||
throws InterruptedException, ExecutionException {
|
||||
|
||||
Future<Boolean> task0 = this.executorService.submit(addTask);
|
||||
Future<Boolean> task1 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task2 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task3 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task4 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task5 = this.executorService.submit(iterateTask);
|
||||
|
||||
run.set(true);
|
||||
Thread.sleep(1000L);
|
||||
run.set(false);
|
||||
|
||||
Boolean result0 = task0.get();
|
||||
Boolean result1 = task1.get();
|
||||
Boolean result2 = task2.get();
|
||||
Boolean result3 = task3.get();
|
||||
Boolean result4 = task4.get();
|
||||
Boolean result5 = task5.get();
|
||||
|
||||
assertTrue(result0);
|
||||
assertTrue(result1);
|
||||
assertTrue(result2);
|
||||
assertTrue(result3);
|
||||
assertTrue(result4);
|
||||
assertTrue(result5);
|
||||
}
|
||||
|
||||
private Boolean addToMap(MapOfLists<String, String> mapOfLists, AtomicBoolean run) {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
addElement(mapOfLists, "Resource", UUID.randomUUID().toString());
|
||||
addElement(mapOfLists, "Resource", UUID.randomUUID().toString());
|
||||
addElement(mapOfLists, "Order", UUID.randomUUID().toString());
|
||||
addElement(mapOfLists, "Order", UUID.randomUUID().toString());
|
||||
addElement(mapOfLists, "Order", UUID.randomUUID().toString());
|
||||
addElement(mapOfLists, "Activity", UUID.randomUUID().toString());
|
||||
addElement(mapOfLists, "Activity", UUID.randomUUID().toString());
|
||||
|
||||
mapOfLists.removeElement("Resource", "Ball");
|
||||
mapOfLists.removeElement("Order", "ToStock");
|
||||
mapOfLists.removeElement("Activity", "ToStock");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addElement(MapOfLists<String, String> mapOfLists, String type, String id) {
|
||||
logger.info("Adding " + type + " " + id);
|
||||
mapOfLists.addElement(type, id);
|
||||
}
|
||||
|
||||
private MapOfLists<String, String> buildMapOfLists() {
|
||||
MapOfLists<String, String> mapOfLists = synchronizedMapOfLists(new MapOfLists<>(true));
|
||||
mapOfLists.addElement("Resource", "Ball");
|
||||
mapOfLists.addElement("Resource", "Car");
|
||||
mapOfLists.addElement("Order", "StockOrder");
|
||||
mapOfLists.addElement("Order", "ToStock");
|
||||
mapOfLists.addElement("Order", "FromStock");
|
||||
mapOfLists.addElement("Activity", "FromStock");
|
||||
mapOfLists.addElement("Activity", "ToStock");
|
||||
|
||||
assertEquals(Arrays.asList("Ball", "Car"), mapOfLists.getList("Resource"));
|
||||
assertNull(mapOfLists.getList("xxx"));
|
||||
return mapOfLists;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package li.strolch.utils.collections;
|
||||
|
||||
import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfMaps;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SynchronizedMapOfMapsTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SynchronizedMapOfMapsTest.class);
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.executorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldForEach() throws ExecutionException, InterruptedException {
|
||||
|
||||
MapOfMaps<String, String, String> mapOfMaps = buildMapOfMaps();
|
||||
AtomicBoolean run = new AtomicBoolean(false);
|
||||
Callable<Boolean> addTask = () -> addToMap(mapOfMaps, run);
|
||||
|
||||
Callable<Boolean> iterateTask = () -> {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
mapOfMaps.forEach(
|
||||
(s, subTypeMap) -> subTypeMap.forEach((s1, s2) -> logger.info(s + " " + s1 + " " + s2)));
|
||||
mapOfMaps.getMap("Resource").forEach((s1, s2) -> logger.info(" " + s1 + " " + s2));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
runTest(addTask, iterateTask, run);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIterate() throws ExecutionException, InterruptedException {
|
||||
|
||||
MapOfMaps<String, String, String> mapOfMaps = buildMapOfMaps();
|
||||
AtomicBoolean run = new AtomicBoolean(false);
|
||||
Callable<Boolean> addTask = () -> addToMap(mapOfMaps, run);
|
||||
Callable<Boolean> iterateTask = () -> {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
Set<String> types = mapOfMaps.keySet();
|
||||
for (String type : types) {
|
||||
Map<String, String> subTypeMap = mapOfMaps.getMap(type);
|
||||
Set<String> subTypes = subTypeMap.keySet();
|
||||
synchronized (mapOfMaps) {
|
||||
for (String subType : subTypes) {
|
||||
logger.info(type + " " + subType + " " + mapOfMaps.getElement(type, subType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mapOfMaps) {
|
||||
Map<String, String> resources = mapOfMaps.getMap("Resource");
|
||||
for (String value : resources.values()) {
|
||||
logger.info("Resource: value: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
runTest(addTask, iterateTask, run);
|
||||
}
|
||||
|
||||
private void runTest(Callable<Boolean> addTask, Callable<Boolean> iterateTask, AtomicBoolean run)
|
||||
throws InterruptedException, ExecutionException {
|
||||
|
||||
Future<Boolean> task0 = this.executorService.submit(addTask);
|
||||
Future<Boolean> task1 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task2 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task3 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task4 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task5 = this.executorService.submit(iterateTask);
|
||||
|
||||
run.set(true);
|
||||
Thread.sleep(1000L);
|
||||
run.set(false);
|
||||
|
||||
Boolean result0 = task0.get();
|
||||
Boolean result1 = task1.get();
|
||||
Boolean result2 = task2.get();
|
||||
Boolean result3 = task3.get();
|
||||
Boolean result4 = task4.get();
|
||||
Boolean result5 = task5.get();
|
||||
|
||||
assertTrue(result0);
|
||||
assertTrue(result1);
|
||||
assertTrue(result2);
|
||||
assertTrue(result3);
|
||||
assertTrue(result4);
|
||||
assertTrue(result5);
|
||||
}
|
||||
|
||||
private Boolean addToMap(MapOfMaps<String, String, String> mapOfMaps, AtomicBoolean run) {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
addElement(mapOfMaps, "Resource", "Ball", UUID.randomUUID().toString());
|
||||
addElement(mapOfMaps, "Resource", "Car", UUID.randomUUID().toString());
|
||||
addElement(mapOfMaps, "Order", "StockOrder", UUID.randomUUID().toString());
|
||||
addElement(mapOfMaps, "Order", "ToStock", UUID.randomUUID().toString());
|
||||
addElement(mapOfMaps, "Order", "FromStock", UUID.randomUUID().toString());
|
||||
addElement(mapOfMaps, "Activity", "FromStock", UUID.randomUUID().toString());
|
||||
addElement(mapOfMaps, "Activity", "ToStock", UUID.randomUUID().toString());
|
||||
|
||||
mapOfMaps.removeElement("Resource", "Ball");
|
||||
mapOfMaps.removeElement("Order", "ToStock");
|
||||
mapOfMaps.removeElement("Activity", "ToStock");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addElement(MapOfMaps<String, String, String> mapOfMaps, String type, String subType, String id) {
|
||||
logger.info("Adding " + type + " " + subType + " " + id);
|
||||
mapOfMaps.addElement(type, subType, id);
|
||||
}
|
||||
|
||||
private MapOfMaps<String, String, String> buildMapOfMaps() {
|
||||
MapOfMaps<String, String, String> mapOfMaps = synchronizedMapOfMaps(new MapOfMaps<>(true));
|
||||
mapOfMaps.addElement("Resource", "Ball", "yellow");
|
||||
mapOfMaps.addElement("Resource", "Car", "car1");
|
||||
mapOfMaps.addElement("Order", "StockOrder", "stockOrder1");
|
||||
mapOfMaps.addElement("Order", "ToStock", "toStock1");
|
||||
mapOfMaps.addElement("Order", "FromStock", "fromStock1");
|
||||
mapOfMaps.addElement("Activity", "FromStock", "fromStock1");
|
||||
mapOfMaps.addElement("Activity", "ToStock", "toStock1");
|
||||
|
||||
assertEquals("yellow", mapOfMaps.getElement("Resource", "Ball"));
|
||||
assertNull(mapOfMaps.getMap("xxx"));
|
||||
return mapOfMaps;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package li.strolch.utils.collections;
|
||||
|
||||
import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfSets;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SynchronizedMapOfSetsTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SynchronizedMapOfSetsTest.class);
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.executorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldForEach() throws ExecutionException, InterruptedException {
|
||||
|
||||
MapOfSets<String, String> mapOfSets = buildMapOfSets();
|
||||
AtomicBoolean run = new AtomicBoolean(false);
|
||||
Callable<Boolean> addTask = () -> addToMap(mapOfSets, run);
|
||||
|
||||
Callable<Boolean> iterateTask = () -> {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
mapOfSets.forEach((s, list) -> list.forEach(s1 -> logger.info(s + " " + s1)));
|
||||
mapOfSets.getSet("Resource").forEach(s1 -> logger.info(" " + s1));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
runTest(addTask, iterateTask, run);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIterate() throws ExecutionException, InterruptedException {
|
||||
|
||||
MapOfSets<String, String> mapOfSets = buildMapOfSets();
|
||||
AtomicBoolean run = new AtomicBoolean(false);
|
||||
Callable<Boolean> addTask = () -> addToMap(mapOfSets, run);
|
||||
Callable<Boolean> iterateTask = () -> {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
Set<String> types = mapOfSets.keySet();
|
||||
for (String type : types) {
|
||||
synchronized (mapOfSets) {
|
||||
for (String id : mapOfSets.getSet(type)) {
|
||||
logger.info(type + " " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mapOfSets) {
|
||||
Set<String> resources = mapOfSets.getSet("Resource");
|
||||
for (String value : resources) {
|
||||
logger.info("Resource: value: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
runTest(addTask, iterateTask, run);
|
||||
}
|
||||
|
||||
private void runTest(Callable<Boolean> addTask, Callable<Boolean> iterateTask, AtomicBoolean run)
|
||||
throws InterruptedException, ExecutionException {
|
||||
|
||||
Future<Boolean> task0 = this.executorService.submit(addTask);
|
||||
Future<Boolean> task1 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task2 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task3 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task4 = this.executorService.submit(iterateTask);
|
||||
Future<Boolean> task5 = this.executorService.submit(iterateTask);
|
||||
|
||||
run.set(true);
|
||||
Thread.sleep(1000L);
|
||||
run.set(false);
|
||||
|
||||
Boolean result0 = task0.get();
|
||||
Boolean result1 = task1.get();
|
||||
Boolean result2 = task2.get();
|
||||
Boolean result3 = task3.get();
|
||||
Boolean result4 = task4.get();
|
||||
Boolean result5 = task5.get();
|
||||
|
||||
assertTrue(result0);
|
||||
assertTrue(result1);
|
||||
assertTrue(result2);
|
||||
assertTrue(result3);
|
||||
assertTrue(result4);
|
||||
assertTrue(result5);
|
||||
}
|
||||
|
||||
private Boolean addToMap(MapOfSets<String, String> mapOfSets, AtomicBoolean run) {
|
||||
for (; ; ) {
|
||||
if (run.get())
|
||||
break;
|
||||
}
|
||||
|
||||
while (run.get()) {
|
||||
addElement(mapOfSets, "Resource", UUID.randomUUID().toString());
|
||||
addElement(mapOfSets, "Resource", UUID.randomUUID().toString());
|
||||
addElement(mapOfSets, "Order", UUID.randomUUID().toString());
|
||||
addElement(mapOfSets, "Order", UUID.randomUUID().toString());
|
||||
addElement(mapOfSets, "Order", UUID.randomUUID().toString());
|
||||
addElement(mapOfSets, "Activity", UUID.randomUUID().toString());
|
||||
addElement(mapOfSets, "Activity", UUID.randomUUID().toString());
|
||||
|
||||
mapOfSets.removeElement("Resource", "Ball");
|
||||
mapOfSets.removeElement("Order", "ToStock");
|
||||
mapOfSets.removeElement("Activity", "ToStock");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addElement(MapOfSets<String, String> mapOfSets, String type, String id) {
|
||||
logger.info("Adding " + type + " " + id);
|
||||
mapOfSets.addElement(type, id);
|
||||
}
|
||||
|
||||
private MapOfSets<String, String> buildMapOfSets() {
|
||||
MapOfSets<String, String> mapOfSets = synchronizedMapOfSets(new MapOfSets<>(true));
|
||||
mapOfSets.addElement("Resource", "Ball");
|
||||
mapOfSets.addElement("Resource", "Car");
|
||||
mapOfSets.addElement("Order", "StockOrder");
|
||||
mapOfSets.addElement("Order", "ToStock");
|
||||
mapOfSets.addElement("Order", "FromStock");
|
||||
mapOfSets.addElement("Activity", "FromStock");
|
||||
mapOfSets.addElement("Activity", "ToStock");
|
||||
|
||||
assertEquals(new HashSet<>(Arrays.asList("Ball", "Car")), mapOfSets.getSet("Resource"));
|
||||
assertNull(mapOfSets.getSet("xxx"));
|
||||
return mapOfSets;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue