I've just stumbled upon a devious detail in
javafx.collections.FXCollections.SynchronizedObservableMap<K, V>. Although
it almost looks like a twin of Collections.synchronizedMap it does not
allow to protect copying or iterating over it the way
Collections.synchronizedMap does.
Example program:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javafx.collections.FXCollections;
public class SyncMap {
public static void main(String[] args) {
Random rnd = new Random();
Map<Integer, Integer> m = Collections.synchronizedMap(new
HashMap<Integer, Integer>());
// Map<Integer, Integer> m =
FXCollections.synchronizedObservableMap(FXCollections.observableHashMap());
Thread t = new Thread(() -> {
while (true) {
m.put(rnd.nextInt(1000), rnd.nextInt());
}
});
t.setDaemon(true);
t.start();
Map<Integer, Integer> c = null;
for (int i = 0; i < 100000; i ++) {
synchronized(m) {
c = new HashMap<>(m);
}
}
System.out.println(c);
}
}
Using Collections.synchronizedMap this works, because we synchronize on m.
If using FXCollections.synchronizedObservableMap this throws
ConcurrentModificationException. The reason is that
SynchronizedObservableMap(ObservableMap<K, V> map) {
this(map, new Object());
}
SynchronizedObservableMap uses a new Object as mutex instead of itself as
seen in
SynchronizedMap(Map<K,V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
}
javafx.collections.FXCollections.SynchronizedObservableMap<K, V>. Although
it almost looks like a twin of Collections.synchronizedMap it does not
allow to protect copying or iterating over it the way
Collections.synchronizedMap does.
Example program:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javafx.collections.FXCollections;
public class SyncMap {
public static void main(String[] args) {
Random rnd = new Random();
Map<Integer, Integer> m = Collections.synchronizedMap(new
HashMap<Integer, Integer>());
// Map<Integer, Integer> m =
FXCollections.synchronizedObservableMap(FXCollections.observableHashMap());
Thread t = new Thread(() -> {
while (true) {
m.put(rnd.nextInt(1000), rnd.nextInt());
}
});
t.setDaemon(true);
t.start();
Map<Integer, Integer> c = null;
for (int i = 0; i < 100000; i ++) {
synchronized(m) {
c = new HashMap<>(m);
}
}
System.out.println(c);
}
}
Using Collections.synchronizedMap this works, because we synchronize on m.
If using FXCollections.synchronizedObservableMap this throws
ConcurrentModificationException. The reason is that
SynchronizedObservableMap(ObservableMap<K, V> map) {
this(map, new Object());
}
SynchronizedObservableMap uses a new Object as mutex instead of itself as
seen in
SynchronizedMap(Map<K,V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
}