com.google.common.collect.Synchronized Maven / Gradle / Ivy
/*
* 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 static com.google.common.base.Preconditions.checkNotNull;
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;
/**
* Synchronized collection views. This class is package-private because it is
* intended for use only by other synchronized wrappers within this package. It
* does not represent a complete set of synchronized wrappers. Also, it's easy
* to misuse.
*
* The returned synchronized collection views are serializable if the backing
* collection and the lock are serializable.
*
* @see Multimaps#synchronizedMultimap
* @see Multisets#synchronizedMultiset
* @author Mike Bostock
*/
final class Synchronized {
private Synchronized() {}
/** Abstract base class for synchronized views. */
static class SynchronizedObject implements Serializable {
private final Object delegate;
protected final Object lock;
public SynchronizedObject(Object delegate, Object lock) {
this.delegate = checkNotNull(delegate);
this.lock = (lock == null) ? this : lock;
}
// No equals and hashCode; see ForwardingObject for details.
@Override public String toString() {
synchronized (lock) {
return delegate.toString();
}
}
private static final long serialVersionUID = -5880321047335989868L;
}
/**
* Returns a synchronized (thread-safe) collection backed by the specified
* collection using the specified lock (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
* lock when iterating over the returned collection:
*
*
Collection<E> s = Synchronized.collection(
* new HashSet<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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, Object lock) {
return new SynchronizedCollection(collection, lock);
}
/** @see Synchronized#collection */
static class SynchronizedCollection extends SynchronizedObject
implements Collection {
@SuppressWarnings("hiding")
private final Collection delegate;
public SynchronizedCollection(Collection delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
public boolean add(E o) {
synchronized (lock) {
return delegate.add(o);
}
}
public boolean addAll(Collection extends E> c) {
synchronized (lock) {
return delegate.addAll(c);
}
}
public void clear() {
synchronized (lock) {
delegate.clear();
}
}
public boolean contains(Object o) {
synchronized (lock) {
return delegate.contains(o);
}
}
public boolean containsAll(Collection> c) {
synchronized (lock) {
return delegate.containsAll(c);
}
}
public boolean isEmpty() {
synchronized (lock) {
return delegate.isEmpty();
}
}
public Iterator iterator() {
return delegate.iterator(); // manually synchronized
}
public boolean remove(Object o) {
synchronized (lock) {
return delegate.remove(o);
}
}
public boolean removeAll(Collection> c) {
synchronized (lock) {
return delegate.removeAll(c);
}
}
public boolean retainAll(Collection> c) {
synchronized (lock) {
return delegate.retainAll(c);
}
}
public int size() {
synchronized (lock) {
return delegate.size();
}
}
public Object[] toArray() {
synchronized (lock) {
return delegate.toArray();
}
}
public T[] toArray(T[] a) {
synchronized (lock) {
return delegate.toArray(a);
}
}
private static final long serialVersionUID = 184628707078353613L;
}
/**
* Returns a synchronized (thread-safe) set backed by the specified set using
* the specified lock (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
* lock when iterating over the returned set:
*
*
Set<E> s = Synchronized.set(new HashSet<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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, Object lock) {
return new SynchronizedSet(set, lock);
}
/** @see Synchronized#set */
static class SynchronizedSet extends SynchronizedCollection
implements Set {
@SuppressWarnings("hiding")
private final Set delegate;
public SynchronizedSet(Set delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
@Override public boolean equals(Object o) {
synchronized (lock) {
return delegate.equals(o);
}
}
@Override public int hashCode() {
synchronized (lock) {
return delegate.hashCode();
}
}
private static final long serialVersionUID = -1182284868190508661L;
}
/**
* Returns a synchronized (thread-safe) sorted set backed by the specified
* sorted set using the specified lock (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
* lock when iterating over the returned sorted set:
*
*
SortedSet<E> s = Synchronized.sortedSet(
* new TreeSet<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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, Object lock) {
return new SynchronizedSortedSet(set, lock);
}
/** @see Synchronized#sortedSet */
static class SynchronizedSortedSet extends SynchronizedSet
implements SortedSet {
@SuppressWarnings("hiding")
private final SortedSet delegate;
public SynchronizedSortedSet(SortedSet delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
public Comparator super E> comparator() {
synchronized (lock) {
return delegate.comparator();
}
}
public SortedSet subSet(E fromElement, E toElement) {
synchronized (lock) {
return sortedSet(delegate.subSet(fromElement, toElement), lock);
}
}
public SortedSet headSet(E toElement) {
synchronized (lock) {
return sortedSet(delegate.headSet(toElement), lock);
}
}
public SortedSet tailSet(E fromElement) {
synchronized (lock) {
return sortedSet(delegate.tailSet(fromElement), lock);
}
}
public E first() {
synchronized (lock) {
return delegate.first();
}
}
public E last() {
synchronized (lock) {
return delegate.last();
}
}
private static final long serialVersionUID = 257153630837525973L;
}
/**
* Returns a synchronized (thread-safe) list backed by the specified list
* using the specified lock (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
* lock when iterating over the returned list:
*
*
List<E> l = Synchronized.list(new ArrayList<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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, Object lock) {
return (list instanceof RandomAccess)
? new SynchronizedRandomAccessList(list, lock)
: new SynchronizedList(list, lock);
}
/** @see Synchronized#list */
static class SynchronizedList extends SynchronizedCollection
implements List {
@SuppressWarnings("hiding")
private final List delegate;
public SynchronizedList(List delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
public void add(int index, E element) {
synchronized (lock) {
delegate.add(index, element);
}
}
public boolean addAll(int index, Collection extends E> c) {
synchronized (lock) {
return delegate.addAll(index, c);
}
}
public E get(int index) {
synchronized (lock) {
return delegate.get(index);
}
}
public int indexOf(Object o) {
synchronized (lock) {
return delegate.indexOf(o);
}
}
public int lastIndexOf(Object o) {
synchronized (lock) {
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 (lock) {
return delegate.remove(index);
}
}
public E set(int index, E element) {
synchronized (lock) {
return delegate.set(index, element);
}
}
public List subList(int fromIndex, int toIndex) {
synchronized (lock) {
return list(delegate.subList(fromIndex, toIndex), lock);
}
}
@Override public boolean equals(Object o) {
synchronized (lock) {
return delegate.equals(o);
}
}
@Override public int hashCode() {
synchronized (lock) {
return delegate.hashCode();
}
}
private static final long serialVersionUID = -774310967040756161L;
}
/** @see Synchronized#list */
static class SynchronizedRandomAccessList extends SynchronizedList
implements RandomAccess {
public SynchronizedRandomAccessList(List list, Object lock) {
super(list, lock);
}
private static final long serialVersionUID = 700333540904833406L;
}
/**
* Returns a synchronized (thread-safe) multiset backed by the specified
* multiset using the specified lock (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
* lock when iterating over the returned multiset:
*
*
Multiset<E> s = Synchronized.multiset(
* new HashMultiset<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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
*/
public static Multiset multiset(Multiset multiset, Object lock) {
return new SynchronizedMultiset(multiset, lock);
}
/** @see Synchronized#multiset */
static class SynchronizedMultiset extends SynchronizedCollection
implements Multiset {
@SuppressWarnings("hiding")
private final Multiset delegate;
private transient volatile Set elementSet;
private transient volatile Set> entrySet;
public SynchronizedMultiset(Multiset delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
public int count(Object o) {
synchronized (lock) {
return delegate.count(o);
}
}
public boolean add(E e, int n) {
synchronized (lock) {
return delegate.add(e, n);
}
}
public int remove(Object o, int n) {
synchronized (lock) {
return delegate.remove(o, n);
}
}
public int removeAllOccurrences(Object o) {
synchronized (lock) {
return delegate.removeAllOccurrences(o);
}
}
public Set elementSet() {
synchronized (lock) {
if (elementSet == null) {
elementSet = typePreservingSet(delegate.elementSet(), lock);
}
return elementSet;
}
}
public Set> entrySet() {
synchronized (lock) {
if (entrySet == null) {
entrySet = typePreservingSet(delegate.entrySet(), lock);
}
return entrySet;
}
}
@Override public boolean equals(Object o) {
synchronized (lock) {
return delegate.equals(o);
}
}
@Override public int hashCode() {
synchronized (lock) {
return delegate.hashCode();
}
}
private static final long serialVersionUID = -1644906276741825553L;
}
/**
* Returns a synchronized (thread-safe) multimap backed by the specified
* multimap using the specified lock (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
* lock when accessing any of the return multimap's collection views:
*
*
Multimap<K,V> m = Synchronized.multimap(
* new HashMultimap<K,V>(), lock);
* ...
* Set<K> s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (lock) {
* Iterator<K> 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, Object lock) {
return new SynchronizedMultimap(multimap, lock);
}
/** @see Synchronized#multimap */
private static class SynchronizedMultimap
implements Multimap, Serializable {
final Multimap delegate;
final Object lock;
transient volatile Set keySet;
transient volatile Collection values;
transient volatile Collection> entries;
transient volatile Map> asMap;
transient volatile Multiset keys;
SynchronizedMultimap(Multimap delegate, Object lock) {
this.delegate = checkNotNull(delegate);
this.lock = (lock == null) ? this : lock;
}
public int size() {
synchronized (lock) {
return delegate.size();
}
}
public boolean isEmpty() {
synchronized (lock) {
return delegate.isEmpty();
}
}
public boolean containsKey(Object key) {
synchronized (lock) {
return delegate.containsKey(key);
}
}
public boolean containsValue(Object value) {
synchronized (lock) {
return delegate.containsValue(value);
}
}
public boolean containsEntry(Object key, Object value) {
synchronized (lock) {
return delegate.containsEntry(key, value);
}
}
public Collection get(K key) {
synchronized (lock) {
return typePreservingCollection(delegate.get(key), lock);
}
}
public boolean put(K key, V value) {
synchronized (lock) {
return delegate.put(key, value);
}
}
public void putAll(K key, Iterable extends V> values) {
synchronized (lock) {
delegate.putAll(key, values);
}
}
public void putAll(Multimap extends K, ? extends V> multimap) {
synchronized (lock) {
delegate.putAll(multimap);
}
}
public Collection replaceValues(K key, Iterable extends V> values) {
synchronized (lock) {
return delegate.replaceValues(key, values); // copy not synchronized
}
}
public boolean remove(Object key, Object value) {
synchronized (lock) {
return delegate.remove(key, value);
}
}
public Collection removeAll(Object key) {
synchronized (lock) {
return delegate.removeAll(key); // copy not synchronized
}
}
public void clear() {
synchronized (lock) {
delegate.clear();
}
}
public Set keySet() {
synchronized (lock) {
if (keySet == null) {
keySet = typePreservingSet(delegate.keySet(), lock);
}
return keySet;
}
}
public Collection values() {
synchronized (lock) {
if (values == null) {
values = collection(delegate.values(), lock);
}
return values;
}
}
public Collection> entries() {
synchronized (lock) {
if (entries == null) {
entries = typePreservingCollection(delegate.entries(), lock);
}
return entries;
}
}
public Map> asMap() {
synchronized (lock) {
if (asMap == null) {
asMap = new SynchronizedAsMap(delegate.asMap(), lock);
}
return asMap;
}
}
public Multiset keys() {
synchronized (lock) {
if (keys == null) {
keys = multiset(delegate.keys(), lock);
}
return keys;
}
}
@Override public boolean equals(Object other) {
synchronized (lock) {
return delegate.equals(other);
}
}
@Override public int hashCode() {
synchronized (lock) {
return delegate.hashCode();
}
}
private static final long serialVersionUID = 7083631791577112787L;
}
/**
* Returns a synchronized (thread-safe) collection backed by the specified
* collection using the specified lock (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
* lock when iterating over the returned collection:
*
*
Collection<E> s = Synchronized.typePreservingCollection(
* new HashSet<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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, Object lock) {
if (collection instanceof SortedSet>) {
return sortedSet((SortedSet) collection, lock);
} else if (collection instanceof Set>) {
return set((Set) collection, lock);
} else if (collection instanceof List>) {
return list((List) collection, lock);
} else {
return collection(collection, lock);
}
}
/**
* Returns a synchronized (thread-safe) set backed by the specified set using
* the specified lock (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
* lock when iterating over the returned collection:
*
*
Set<E> s = Synchronized.typePreservingSet(
* new HashSet<E>(), lock);
* ...
* synchronized (lock) {
* Iterator<E> 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, Object lock) {
if (set instanceof SortedSet>) {
return sortedSet((SortedSet) set, lock);
} else {
return set(set, lock);
}
}
/** @see Synchronized#multimap */
static class SynchronizedAsMapEntries
extends SynchronizedSet>> {
@SuppressWarnings("hiding")
private final Set>> delegate;
public SynchronizedAsMapEntries(
Set>> delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
@Override public Iterator>> iterator() {
// The iterator and entry aren't synchronized, but the entry value is.
return new ForwardingIterator>>(
super.iterator()) {
@Override public Map.Entry> next() {
return new ForwardingMapEntry>(super.next()) {
@Override public Collection getValue() {
return typePreservingCollection(super.getValue(), lock);
}
};
}
};
}
// See java.util.Collections.CheckedEntrySet for details on attacks.
@Override public Object[] toArray() {
synchronized (lock) {
return ForwardingCollection.toArrayImpl(this);
}
}
@Override public T[] toArray(T[] array) {
synchronized (lock) {
return ForwardingCollection.toArrayImpl(this, array);
}
}
@Override public boolean contains(Object o) {
synchronized (lock) {
return Maps.containsEntryImpl(delegate, o);
}
}
@Override public boolean containsAll(Collection> c) {
synchronized (lock) {
return ForwardingCollection.containsAllImpl(this, c);
}
}
@Override public boolean equals(Object o) {
synchronized (lock) {
return ForwardingSet.equalsImpl(this, o);
}
}
@Override public boolean remove(Object o) {
synchronized (lock) {
return Maps.removeEntryImpl(delegate, o);
}
}
@Override public boolean removeAll(Collection> c) {
synchronized (lock) {
return ForwardingCollection.removeAllImpl(this, c);
}
}
@Override public boolean retainAll(Collection> c) {
synchronized (lock) {
return ForwardingCollection.retainAllImpl(this, c);
}
}
private static final long serialVersionUID = 794109514199117015L;
}
/**
* Returns a synchronized (thread-safe) map backed by the specified map using
* the specified lock (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
* lock when accessing any of the return map's collection views:
*
*
Map<K,V> m = Synchronized.map(
* new HashMap<K,V>(), lock);
* ...
* Set<K> s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (lock) {
* Iterator<K> 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, Object lock) {
return new SynchronizedMap(map, lock);
}
/** @see Synchronized#map */
static class SynchronizedMap implements Map, Serializable {
private final Map delegate;
protected final Object lock;
private transient volatile Set keySet;
private transient volatile Collection values;
private transient volatile Set> entrySet;
public SynchronizedMap(Map delegate, Object lock) {
this.delegate = checkNotNull(delegate);
this.lock = (lock == null) ? this : lock;
}
public void clear() {
synchronized (lock) {
delegate.clear();
}
}
public boolean containsKey(Object key) {
synchronized (lock) {
return delegate.containsKey(key);
}
}
public boolean containsValue(Object value) {
synchronized (lock) {
return delegate.containsValue(value);
}
}
public Set> entrySet() {
synchronized (lock) {
if (entrySet == null) {
entrySet = set(delegate.entrySet(), lock);
}
return entrySet;
}
}
public V get(Object key) {
synchronized (lock) {
return delegate.get(key);
}
}
public boolean isEmpty() {
synchronized (lock) {
return delegate.isEmpty();
}
}
public Set keySet() {
synchronized (lock) {
if (keySet == null) {
keySet = set(delegate.keySet(), lock);
}
return keySet;
}
}
public V put(K key, V value) {
synchronized (lock) {
return delegate.put(key, value);
}
}
public void putAll(Map extends K, ? extends V> t) {
synchronized (lock) {
delegate.putAll(t);
}
}
public V remove(Object key) {
synchronized (lock) {
return delegate.remove(key);
}
}
public int size() {
synchronized (lock) {
return delegate.size();
}
}
public Collection values() {
synchronized (lock) {
if (values == null) {
values = collection(delegate.values(), lock);
}
return values;
}
}
@Override public String toString() {
synchronized (lock) {
return delegate.toString();
}
}
@Override public boolean equals(Object other) {
synchronized (lock) {
return delegate.equals(other);
}
}
@Override public int hashCode() {
synchronized (lock) {
return delegate.hashCode();
}
}
private static final long serialVersionUID = -2739593476673006162L;
}
/**
* Returns a synchronized (thread-safe) bimap backed by the specified bimap
* using the specified lock (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
* lock when accessing any of the return bimap's collection views:
*
*
BiMap<K,V> m = Synchronized.biMap(
* new HashBiMap<K,V>(), lock);
* ...
* Set<K> s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (lock) {
* Iterator<K> 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, Object lock) {
return new SynchronizedBiMap(bimap, lock, null);
}
/** @see Synchronized#biMap */
static class SynchronizedBiMap extends SynchronizedMap
implements BiMap, Serializable {
@SuppressWarnings("hiding")
private final BiMap delegate;
@SuppressWarnings("hiding")
private transient volatile Set values;
private transient volatile BiMap inverse;
public SynchronizedBiMap(
BiMap delegate, Object lock, BiMap inverse) {
super(delegate, lock);
this.delegate = delegate;
this.inverse = inverse;
}
@Override public Set values() {
synchronized (lock) {
if (values == null) {
values = set(delegate.values(), lock);
}
return values;
}
}
public V forcePut(K key, V value) {
synchronized (lock) {
return delegate.forcePut(key, value);
}
}
public BiMap inverse() {
synchronized (lock) {
if (inverse == null) {
inverse = new SynchronizedBiMap(delegate.inverse(), lock, this);
}
return inverse;
}
}
private static final long serialVersionUID = -8892589047022295017L;
}
/** @see SynchronizedMultimap#asMap */
static class SynchronizedAsMap
extends SynchronizedMap> {
@SuppressWarnings("hiding")
private final Map> delegate;
@SuppressWarnings("hiding")
private transient volatile Set>> entrySet;
@SuppressWarnings("hiding")
private transient volatile Collection> values;
public SynchronizedAsMap(Map> delegate, Object lock) {
super(delegate, lock);
this.delegate = delegate;
}
@Override public Collection get(Object key) {
synchronized (lock) {
Collection collection = super.get(key);
return (collection == null) ? null :
typePreservingCollection(collection, lock);
}
}
@Override public Set>> entrySet() {
if (entrySet == null) {
entrySet = new SynchronizedAsMapEntries(
delegate.entrySet(), lock);
}
return entrySet;
}
@Override public Collection> values() {
if (values == null) {
values = new SynchronizedAsMapValues(delegate.values(), lock);
}
return values;
}
@Override public boolean containsValue(Object o) {
return values().contains(o);
}
private static final long serialVersionUID = 794109514199117015L;
}
/** @see SynchronizedMultimap#asMap */
static class SynchronizedAsMapValues
extends SynchronizedCollection> {
SynchronizedAsMapValues(Collection> delegate, Object lock) {
super(delegate, lock);
}
@Override public Iterator> iterator() {
// The iterator isn't synchronized, but its value is.
return new ForwardingIterator>(super.iterator()) {
@Override public Collection next() {
return typePreservingCollection(super.next(), lock);
}
};
}
// See java.util.Collections.CheckedEntrySet for details on attacks.
@Override public Object[] toArray() {
synchronized (lock) {
return ForwardingCollection.toArrayImpl(this);
}
}
@Override public T[] toArray(T[] array) {
synchronized (lock) {
return ForwardingCollection.toArrayImpl(this, array);
}
}
@Override public boolean contains(Object o) {
synchronized (lock) {
return ForwardingCollection.containsImpl(this, o);
}
}
@Override public boolean containsAll(Collection> c) {
synchronized (lock) {
return ForwardingCollection.containsAllImpl(this, c);
}
}
@Override public boolean remove(Object o) {
synchronized (lock) {
return ForwardingCollection.removeImpl(this, o);
}
}
@Override public boolean removeAll(Collection> c) {
synchronized (lock) {
return ForwardingCollection.removeAllImpl(this, c);
}
}
@Override public boolean retainAll(Collection> c) {
synchronized (lock) {
return ForwardingCollection.retainAllImpl(this, c);
}
}
private static final long serialVersionUID = 794109514199117015L;
}
}