com.google.common.collect.Synchronized Maven / Gradle / Ivy
Show all versions of google-collections Show documentation
/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedSet;
import javax.annotation.Nullable;
/**
* Synchronized collection views. The returned synchronized collection views are
* serializable if the backing collection and the mutex are serializable.
*
* If a {@code null} is passed as the {@code mutex} parameter to any of this
* class's top-level methods or inner class constructors, the created object
* uses itself as the synchronization mutex.
*
*
This class should be used by other collection classes only.
*
* @author Mike Bostock
* @author Jared Levy
*/
@GwtCompatible
final class Synchronized {
private Synchronized() {}
/** Abstract base class for synchronized views. */
static class SynchronizedObject implements Serializable {
private final Object delegate;
protected final Object mutex;
public SynchronizedObject(Object delegate, @Nullable Object mutex) {
this.delegate = checkNotNull(delegate);
this.mutex = (mutex == null) ? this : mutex;
}
protected Object delegate() {
return delegate;
}
// No equals and hashCode; see ForwardingObject for details.
@Override public String toString() {
synchronized (mutex) {
return delegate.toString();
}
}
// Serialization invokes writeObject only when it's private.
// The SynchronizedObject subclasses don't need a writeObject method since
// they don't contain any non-transient member variables, while the
// following writeObject() handles the SynchronizedObject members.
private void writeObject(ObjectOutputStream stream) throws IOException {
synchronized (mutex) {
stream.defaultWriteObject();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) collection backed by the specified
* collection using the specified mutex. In order to guarantee serial access,
* it is critical that all access to the backing collection is
* accomplished through the returned collection.
*
*
It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned collection:
{@code
*
* Collection s = Synchronized.collection(
* new HashSet(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param collection the collection to be wrapped in a synchronized view
* @return a synchronized view of the specified collection
*/
static Collection collection(
Collection collection, @Nullable Object mutex) {
return new SynchronizedCollection(collection, mutex);
}
/** @see Synchronized#collection */
static class SynchronizedCollection extends SynchronizedObject
implements Collection {
public SynchronizedCollection(
Collection delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@SuppressWarnings("unchecked")
@Override protected Collection delegate() {
return (Collection) super.delegate();
}
public boolean add(E e) {
synchronized (mutex) {
return delegate().add(e);
}
}
public boolean addAll(Collection extends E> c) {
synchronized (mutex) {
return delegate().addAll(c);
}
}
public void clear() {
synchronized (mutex) {
delegate().clear();
}
}
public boolean contains(Object o) {
synchronized (mutex) {
return delegate().contains(o);
}
}
public boolean containsAll(Collection> c) {
synchronized (mutex) {
return delegate().containsAll(c);
}
}
public boolean isEmpty() {
synchronized (mutex) {
return delegate().isEmpty();
}
}
public Iterator iterator() {
return delegate().iterator(); // manually synchronized
}
public boolean remove(Object o) {
synchronized (mutex) {
return delegate().remove(o);
}
}
public boolean removeAll(Collection> c) {
synchronized (mutex) {
return delegate().removeAll(c);
}
}
public boolean retainAll(Collection> c) {
synchronized (mutex) {
return delegate().retainAll(c);
}
}
public int size() {
synchronized (mutex) {
return delegate().size();
}
}
public Object[] toArray() {
synchronized (mutex) {
return delegate().toArray();
}
}
public T[] toArray(T[] a) {
synchronized (mutex) {
return delegate().toArray(a);
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) set backed by the specified set using
* the specified mutex. In order to guarantee serial access, it is critical
* that all access to the backing set is accomplished through the
* returned set.
*
* It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned set:
{@code
*
* Set s = Synchronized.set(new HashSet(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param set the set to be wrapped in a synchronized view
* @return a synchronized view of the specified set
*/
public static Set set(Set set, @Nullable Object mutex) {
return new SynchronizedSet(set, mutex);
}
/** @see Synchronized#set */
static class SynchronizedSet extends SynchronizedCollection
implements Set {
public SynchronizedSet(Set delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected Set delegate() {
return (Set) super.delegate();
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) sorted set backed by the specified
* sorted set using the specified mutex. In order to guarantee serial access,
* it is critical that all access to the backing sorted set is
* accomplished through the returned sorted set.
*
* It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned sorted set:
{@code
*
* SortedSet s = Synchronized.sortedSet(
* new TreeSet(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param set the sorted set to be wrapped in a synchronized view
* @return a synchronized view of the specified sorted set
*/
static SortedSet sortedSet(SortedSet set, @Nullable Object mutex) {
return new SynchronizedSortedSet(set, mutex);
}
/** @see Synchronized#sortedSet */
static class SynchronizedSortedSet extends SynchronizedSet
implements SortedSet {
public SynchronizedSortedSet(
SortedSet delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected SortedSet delegate() {
return (SortedSet) super.delegate();
}
public Comparator super E> comparator() {
synchronized (mutex) {
return delegate().comparator();
}
}
public SortedSet subSet(E fromElement, E toElement) {
synchronized (mutex) {
return sortedSet(delegate().subSet(fromElement, toElement), mutex);
}
}
public SortedSet headSet(E toElement) {
synchronized (mutex) {
return sortedSet(delegate().headSet(toElement), mutex);
}
}
public SortedSet tailSet(E fromElement) {
synchronized (mutex) {
return sortedSet(delegate().tailSet(fromElement), mutex);
}
}
public E first() {
synchronized (mutex) {
return delegate().first();
}
}
public E last() {
synchronized (mutex) {
return delegate().last();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) list backed by the specified list
* using the specified mutex. In order to guarantee serial access, it is
* critical that all access to the backing list is accomplished
* through the returned list.
*
* It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned list:
{@code
*
* List l = Synchronized.list(new ArrayList(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = l.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* The returned list implements {@link RandomAccess} if the specified list
* implements {@code RandomAccess}.
*
* @param list the list to be wrapped in a synchronized view
* @return a synchronized view of the specified list
*/
static List list(List list, @Nullable Object mutex) {
return (list instanceof RandomAccess)
? new SynchronizedRandomAccessList(list, mutex)
: new SynchronizedList(list, mutex);
}
/** @see Synchronized#list */
static class SynchronizedList extends SynchronizedCollection
implements List {
public SynchronizedList(List delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected List delegate() {
return (List) super.delegate();
}
public void add(int index, E element) {
synchronized (mutex) {
delegate().add(index, element);
}
}
public boolean addAll(int index, Collection extends E> c) {
synchronized (mutex) {
return delegate().addAll(index, c);
}
}
public E get(int index) {
synchronized (mutex) {
return delegate().get(index);
}
}
public int indexOf(Object o) {
synchronized (mutex) {
return delegate().indexOf(o);
}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {
return delegate().lastIndexOf(o);
}
}
public ListIterator listIterator() {
return delegate().listIterator(); // manually synchronized
}
public ListIterator listIterator(int index) {
return delegate().listIterator(index); // manually synchronized
}
public E remove(int index) {
synchronized (mutex) {
return delegate().remove(index);
}
}
public E set(int index, E element) {
synchronized (mutex) {
return delegate().set(index, element);
}
}
@GwtIncompatible("List.subList")
public List subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return list(Platform.subList(delegate(), fromIndex, toIndex), mutex);
}
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
/** @see Synchronized#list */
static class SynchronizedRandomAccessList extends SynchronizedList
implements RandomAccess {
public SynchronizedRandomAccessList(List list, @Nullable Object mutex) {
super(list, mutex);
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) multiset backed by the specified
* multiset using the specified mutex. In order to guarantee serial access, it
* is critical that all access to the backing multiset is accomplished
* through the returned multiset.
*
* It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned multiset:
{@code
*
* Multiset s = Synchronized.multiset(
* HashMultiset.create(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param multiset the multiset to be wrapped
* @return a synchronized view of the specified multiset
*/
private static Multiset multiset(
Multiset multiset, @Nullable Object mutex) {
return new SynchronizedMultiset(multiset, mutex);
}
/** @see Synchronized#multiset */
static class SynchronizedMultiset extends SynchronizedCollection
implements Multiset {
private transient Set elementSet;
private transient Set> entrySet;
public SynchronizedMultiset(Multiset delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected Multiset delegate() {
return (Multiset) super.delegate();
}
public int count(Object o) {
synchronized (mutex) {
return delegate().count(o);
}
}
public int add(E e, int n) {
synchronized (mutex) {
return delegate().add(e, n);
}
}
public int remove(Object o, int n) {
synchronized (mutex) {
return delegate().remove(o, n);
}
}
public int setCount(E element, int count) {
synchronized (mutex) {
return delegate().setCount(element, count);
}
}
public boolean setCount(E element, int oldCount, int newCount) {
synchronized (mutex) {
return delegate().setCount(element, oldCount, newCount);
}
}
public Set elementSet() {
synchronized (mutex) {
if (elementSet == null) {
elementSet = typePreservingSet(delegate().elementSet(), mutex);
}
return elementSet;
}
}
public Set> entrySet() {
synchronized (mutex) {
if (entrySet == null) {
entrySet = typePreservingSet(delegate().entrySet(), mutex);
}
return entrySet;
}
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) multimap backed by the specified
* multimap using the specified mutex. In order to guarantee serial access, it
* is critical that all access to the backing multimap is accomplished
* through the returned multimap.
*
* It is imperative that the user manually synchronize on the specified
* mutex when accessing any of the return multimap's collection views:
*
{@code
*
* Multimap m = Synchronized.multimap(
* HashMultimap.create(), mutex);
* ...
* Set s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param multimap the multimap to be wrapped in a synchronized view
* @return a synchronized view of the specified multimap
*/
public static Multimap multimap(
Multimap multimap, @Nullable Object mutex) {
return new SynchronizedMultimap(multimap, mutex);
}
/** @see Synchronized#multimap */
private static class SynchronizedMultimap extends SynchronizedObject
implements Multimap {
transient Set keySet;
transient Collection valuesCollection;
transient Collection> entries;
transient Map> asMap;
transient Multiset keys;
@SuppressWarnings("unchecked")
@Override protected Multimap delegate() {
return (Multimap) super.delegate();
}
SynchronizedMultimap(Multimap delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
public int size() {
synchronized (mutex) {
return delegate().size();
}
}
public boolean isEmpty() {
synchronized (mutex) {
return delegate().isEmpty();
}
}
public boolean containsKey(Object key) {
synchronized (mutex) {
return delegate().containsKey(key);
}
}
public boolean containsValue(Object value) {
synchronized (mutex) {
return delegate().containsValue(value);
}
}
public boolean containsEntry(Object key, Object value) {
synchronized (mutex) {
return delegate().containsEntry(key, value);
}
}
public Collection get(K key) {
synchronized (mutex) {
return typePreservingCollection(delegate().get(key), mutex);
}
}
public boolean put(K key, V value) {
synchronized (mutex) {
return delegate().put(key, value);
}
}
public boolean putAll(K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().putAll(key, values);
}
}
public boolean putAll(Multimap extends K, ? extends V> multimap) {
synchronized (mutex) {
return delegate().putAll(multimap);
}
}
public Collection replaceValues(K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
public boolean remove(Object key, Object value) {
synchronized (mutex) {
return delegate().remove(key, value);
}
}
public Collection removeAll(Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
public void clear() {
synchronized (mutex) {
delegate().clear();
}
}
public Set keySet() {
synchronized (mutex) {
if (keySet == null) {
keySet = typePreservingSet(delegate().keySet(), mutex);
}
return keySet;
}
}
public Collection values() {
synchronized (mutex) {
if (valuesCollection == null) {
valuesCollection = collection(delegate().values(), mutex);
}
return valuesCollection;
}
}
public Collection> entries() {
synchronized (mutex) {
if (entries == null) {
entries = typePreservingCollection(delegate().entries(), mutex);
}
return entries;
}
}
public Map> asMap() {
synchronized (mutex) {
if (asMap == null) {
asMap = new SynchronizedAsMap(delegate().asMap(), mutex);
}
return asMap;
}
}
public Multiset keys() {
synchronized (mutex) {
if (keys == null) {
keys = multiset(delegate().keys(), mutex);
}
return keys;
}
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) list multimap backed by the specified
* multimap using the specified mutex.
*
* You must follow the warnings described for {@link #multimap}.
*
* @param multimap the multimap to be wrapped in a synchronized view
* @return a synchronized view of the specified multimap
*/
public static ListMultimap listMultimap(
ListMultimap multimap, @Nullable Object mutex) {
return new SynchronizedListMultimap(multimap, mutex);
}
/** @see Synchronized#listMultimap */
private static class SynchronizedListMultimap
extends SynchronizedMultimap implements ListMultimap {
SynchronizedListMultimap(
ListMultimap delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected ListMultimap delegate() {
return (ListMultimap) super.delegate();
}
@Override public List get(K key) {
synchronized (mutex) {
return list(delegate().get(key), mutex);
}
}
@Override public List removeAll(Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override public List replaceValues(
K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) set multimap backed by the specified
* multimap using the specified mutex.
*
* You must follow the warnings described for {@link #multimap}.
*
* @param multimap the multimap to be wrapped in a synchronized view
* @return a synchronized view of the specified multimap
*/
public static SetMultimap setMultimap(
SetMultimap multimap, @Nullable Object mutex) {
return new SynchronizedSetMultimap(multimap, mutex);
}
/** @see Synchronized#setMultimap */
private static class SynchronizedSetMultimap
extends SynchronizedMultimap implements SetMultimap {
transient Set> entrySet;
SynchronizedSetMultimap(
SetMultimap delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected SetMultimap delegate() {
return (SetMultimap) super.delegate();
}
@Override public Set get(K key) {
synchronized (mutex) {
return set(delegate().get(key), mutex);
}
}
@Override public Set removeAll(Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override public Set replaceValues(
K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
@Override public Set> entries() {
synchronized (mutex) {
if (entrySet == null) {
entrySet = set(delegate().entries(), mutex);
}
return entrySet;
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) sorted set multimap backed by the
* specified multimap using the specified mutex.
*
* You must follow the warnings described for {@link #multimap}.
*
* @param multimap the multimap to be wrapped in a synchronized view
* @return a synchronized view of the specified multimap
*/
public static SortedSetMultimap sortedSetMultimap(
SortedSetMultimap multimap, @Nullable Object mutex) {
return new SynchronizedSortedSetMultimap(multimap, mutex);
}
/** @see Synchronized#sortedSetMultimap */
private static class SynchronizedSortedSetMultimap
extends SynchronizedSetMultimap implements SortedSetMultimap {
SynchronizedSortedSetMultimap(
SortedSetMultimap delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override protected SortedSetMultimap delegate() {
return (SortedSetMultimap) super.delegate();
}
@Override public SortedSet get(K key) {
synchronized (mutex) {
return sortedSet(delegate().get(key), mutex);
}
}
@Override public SortedSet removeAll(Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override public SortedSet replaceValues(
K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
public Comparator super V> valueComparator() {
synchronized (mutex) {
return delegate().valueComparator();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) collection backed by the specified
* collection using the specified mutex. In order to guarantee serial access,
* it is critical that all access to the backing collection is
* accomplished through the returned collection.
*
* It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned collection:
{@code
*
* Collection s = Synchronized.typePreservingCollection(
* new HashSet(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* If the specified collection is a {@code SortedSet}, {@code Set} or
* {@code List}, this method will behave identically to {@link #sortedSet},
* {@link #set} or {@link #list} respectively, in that order of specificity.
*
* @param collection the collection to be wrapped in a synchronized view
* @return a synchronized view of the specified collection
*/
private static Collection typePreservingCollection(
Collection collection, @Nullable Object mutex) {
if (collection instanceof SortedSet) {
return sortedSet((SortedSet) collection, mutex);
} else if (collection instanceof Set) {
return set((Set) collection, mutex);
} else if (collection instanceof List) {
return list((List) collection, mutex);
} else {
return collection(collection, mutex);
}
}
/**
* Returns a synchronized (thread-safe) set backed by the specified set using
* the specified mutex. In order to guarantee serial access, it is critical
* that all access to the backing collection is accomplished through
* the returned collection.
*
* It is imperative that the user manually synchronize on the specified
* mutex when iterating over the returned collection:
{@code
*
* Set s = Synchronized.typePreservingSet(
* new HashSet(), mutex);
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* If the specified collection is a {@code SortedSet} this method will
* behave identically to {@link #sortedSet}.
*
* @param set the set to be wrapped in a synchronized view
* @return a synchronized view of the specified set
*/
public static Set typePreservingSet(
Set set, @Nullable Object mutex) {
if (set instanceof SortedSet) {
return sortedSet((SortedSet) set, mutex);
} else {
return set(set, mutex);
}
}
/** @see Synchronized#multimap */
static class SynchronizedAsMapEntries
extends SynchronizedSet>> {
public SynchronizedAsMapEntries(
Set>> delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override public Iterator>> iterator() {
// Must be manually synchronized.
final Iterator>> iterator = super.iterator();
return new ForwardingIterator>>() {
@Override protected Iterator>> delegate() {
return iterator;
}
@Override public Map.Entry> next() {
final Map.Entry> entry = iterator.next();
return new ForwardingMapEntry>() {
@Override protected Map.Entry> delegate() {
return entry;
}
@Override public Collection getValue() {
return typePreservingCollection(entry.getValue(), mutex);
}
};
}
};
}
// See Collections.CheckedMap.CheckedEntrySet for details on attacks.
@Override public Object[] toArray() {
synchronized (mutex) {
return ObjectArrays.toArrayImpl(delegate());
}
}
@Override public T[] toArray(T[] array) {
synchronized (mutex) {
return ObjectArrays.toArrayImpl(delegate(), array);
}
}
@Override public boolean contains(Object o) {
synchronized (mutex) {
return Maps.containsEntryImpl(delegate(), o);
}
}
@Override public boolean containsAll(Collection> c) {
synchronized (mutex) {
return Collections2.containsAll(delegate(), c);
}
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return Collections2.setEquals(delegate(), o);
}
}
@Override public boolean remove(Object o) {
synchronized (mutex) {
return Maps.removeEntryImpl(delegate(), o);
}
}
@Override public boolean removeAll(Collection> c) {
synchronized (mutex) {
return Iterators.removeAll(delegate().iterator(), c);
}
}
@Override public boolean retainAll(Collection> c) {
synchronized (mutex) {
return Iterators.retainAll(delegate().iterator(), c);
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) map backed by the specified map using
* the specified mutex. In order to guarantee serial access, it is critical
* that all access to the backing map is accomplished through the
* returned map.
*
* It is imperative that the user manually synchronize on the specified
* mutex when accessing any of the return map's collection views:
*
{@code
*
* Map m = Synchronized.map(
* new HashMap(), mutex);
* ...
* Set s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param map the map to be wrapped in a synchronized view
* @return a synchronized view of the specified map
*/
public static Map map(Map map, @Nullable Object mutex) {
return new SynchronizedMap(map, mutex);
}
/** @see Synchronized#map */
static class SynchronizedMap extends SynchronizedObject
implements Map {
private transient Set keySet;
private transient Collection values;
private transient Set> entrySet;
public SynchronizedMap(Map delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@SuppressWarnings("unchecked")
@Override protected Map delegate() {
return (Map) super.delegate();
}
public void clear() {
synchronized (mutex) {
delegate().clear();
}
}
public boolean containsKey(Object key) {
synchronized (mutex) {
return delegate().containsKey(key);
}
}
public boolean containsValue(Object value) {
synchronized (mutex) {
return delegate().containsValue(value);
}
}
public Set> entrySet() {
synchronized (mutex) {
if (entrySet == null) {
entrySet = set(delegate().entrySet(), mutex);
}
return entrySet;
}
}
public V get(Object key) {
synchronized (mutex) {
return delegate().get(key);
}
}
public boolean isEmpty() {
synchronized (mutex) {
return delegate().isEmpty();
}
}
public Set keySet() {
synchronized (mutex) {
if (keySet == null) {
keySet = set(delegate().keySet(), mutex);
}
return keySet;
}
}
public V put(K key, V value) {
synchronized (mutex) {
return delegate().put(key, value);
}
}
public void putAll(Map extends K, ? extends V> map) {
synchronized (mutex) {
delegate().putAll(map);
}
}
public V remove(Object key) {
synchronized (mutex) {
return delegate().remove(key);
}
}
public int size() {
synchronized (mutex) {
return delegate().size();
}
}
public Collection values() {
synchronized (mutex) {
if (values == null) {
values = collection(delegate().values(), mutex);
}
return values;
}
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) bimap backed by the specified bimap
* using the specified mutex. In order to guarantee serial access, it is
* critical that all access to the backing bimap is accomplished
* through the returned bimap.
*
* It is imperative that the user manually synchronize on the specified
* mutex when accessing any of the return bimap's collection views:
*
{@code
*
* BiMap m = Synchronized.biMap(
* HashBiMap.create(), mutex);
* ...
* Set s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (mutex) {
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }}
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* @param bimap the bimap to be wrapped in a synchronized view
* @return a synchronized view of the specified bimap
*/
public static BiMap biMap(
BiMap bimap, @Nullable Object mutex) {
return new SynchronizedBiMap(bimap, mutex, null);
}
/** @see Synchronized#biMap */
static class SynchronizedBiMap extends SynchronizedMap
implements BiMap, Serializable {
private transient Set valueSet;
private transient BiMap inverse;
public SynchronizedBiMap(
BiMap delegate, @Nullable Object mutex,
@Nullable BiMap inverse) {
super(delegate, mutex);
this.inverse = inverse;
}
@Override protected BiMap delegate() {
return (BiMap) super.delegate();
}
@Override public Set values() {
synchronized (mutex) {
if (valueSet == null) {
valueSet = set(delegate().values(), mutex);
}
return valueSet;
}
}
public V forcePut(K key, V value) {
synchronized (mutex) {
return delegate().forcePut(key, value);
}
}
public BiMap inverse() {
synchronized (mutex) {
if (inverse == null) {
inverse
= new SynchronizedBiMap(delegate().inverse(), mutex, this);
}
return inverse;
}
}
private static final long serialVersionUID = 0;
}
/** @see SynchronizedMultimap#asMap */
static class SynchronizedAsMap
extends SynchronizedMap> {
private transient Set>> asMapEntrySet;
private transient Collection> asMapValues;
public SynchronizedAsMap(
Map> delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override public Collection get(Object key) {
synchronized (mutex) {
Collection collection = super.get(key);
return (collection == null) ? null
: typePreservingCollection(collection, mutex);
}
}
@Override public Set>> entrySet() {
synchronized (mutex) {
if (asMapEntrySet == null) {
asMapEntrySet = new SynchronizedAsMapEntries(
delegate().entrySet(), mutex);
}
return asMapEntrySet;
}
}
@Override public Collection> values() {
synchronized (mutex) {
if (asMapValues == null) {
asMapValues
= new SynchronizedAsMapValues(delegate().values(), mutex);
}
return asMapValues;
}
}
@Override public boolean containsValue(Object o) {
// values() and its contains() method are both synchronized.
return values().contains(o);
}
private static final long serialVersionUID = 0;
}
/** @see SynchronizedMultimap#asMap */
static class SynchronizedAsMapValues
extends SynchronizedCollection> {
SynchronizedAsMapValues(
Collection> delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@Override public Iterator> iterator() {
// Must be manually synchronized.
final Iterator> iterator = super.iterator();
return new ForwardingIterator>() {
@Override protected Iterator> delegate() {
return iterator;
}
@Override public Collection next() {
return typePreservingCollection(iterator.next(), mutex);
}
};
}
private static final long serialVersionUID = 0;
}
}