I was looking at java code for Collections.synhronizedMap().I found that it has below implementation.Now my question is 1) why are we using synchronized(mutex) 2) what if we use synchronized(m)
I understanding is that if we do synchronized(m) then also only one thread will be able to access the map.
static class SynchronizedMap<K, V> implements Map<K, V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L;
private final Map<K, V> m;
final Object mutex;
SynchronizedMap(Map<K, V> map) {
m = map;
mutex = this;
}
SynchronizedMap(Map<K, V> map, Object mutex) {
m = map;
this.mutex = mutex;
}
public void clear() {
synchronized (mutex) {
m.clear();
}
}
public boolean containsKey(Object key) {
synchronized (mutex) {
return m.containsKey(key);
}
}
public boolean containsValue(Object value) {
synchronized (mutex) {
return m.containsValue(value);
}
}
public Set<Map.Entry<K, V>> entrySet() {
synchronized (mutex) {
return new SynchronizedSet<Map.Entry<K, V>>(m.entrySet(), mutex);
}
}
@Override
public boolean equals(Object object) {
synchronized (mutex) {
return m.equals(object);
}
}
Edit:I want few clarifications which are also relevant to this question
1) Java’s this keyword is used to refer the current instance of the method on which it is used. So if i am putting mutex on this keyword then does it mean that we will lock the current instance of the object or we will lock the current instance of thread? I would be grateful if somebody can explain a meaning of following statement in a more holistic manner
mutex = this;
In either case only one thread can access the map contents at a time.
It is better style to have a mutex separate from the map. If the map passed in is having other threads synchronize on it then that doesn't affect this object. Separating the lock from the map lets the user specify the lock separately, so it allows the user to share a lock with something else.
This class was written in a way to let it use a lock from outside of itself, or to use itself as a lock. Why is not apparent since there's no context given, I assume there's a case where a coarse-grained locking is needed across this map and something else too.
I would prefer something like
private final Object mutex;
public SynchronizedMap(Map<K,V> map, Object mutex) {
m = map;
this.mutex = mutex;
}
public SynchronizedMap(Map<K,V> map) {
this(map, new Object());
}
because this way there is at least the option of having a lock exclusively under the control of the object.
this here is referring to the SynchronizedMap object.
BTW, probably it doesn't use a private lock so that it can support client-side locking.
As already pointed out in the other answer: In general, and as a rule of thumb, it is preferable to have an explicit, dedicated, private "lock" object, instead of exposing the synchronized via public methods (In the latter case, the object itself will be the lock, and this may easily lead to deadlocks in certain situations)
However, the situation is a bit different here, because all this refers to a private inner class of the Collections class. Particularly, the main reason why there is an explicit mutex parameter is that this mutex can be shared among several instances. The constructor
SynchronizedMap(Map<K,V> m, Object mutex)
is (only!) called in a subclass, namely in
SynchronizedSortedMap(SortedMap<K,V> m, Object mutex) {
super(m, mutex);
sm = m;
}
which just passes the given mutex through to the SynchronizedMap. This constructor, in turn, is called in the subMap, tailMap and headMap methods of the SynchronizedSortedSet class. For example:
public SortedMap<K,V> subMap(K fromKey, K toKey) {
synchronized (mutex) {
return new SynchronizedSortedMap<>(
sm.subMap(fromKey, toKey), mutex);
}
}
Here, the mutex of the actual map is passed to the sub-maps as well.
So the effect here is that the same mutex is used for the map and its sub-maps. This would simply not possible if the synchronization in SynchronizedMap was synchronizing on the delegate map with synchronized(m).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With