All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.collect.Synchronized Maven / Gradle / Ivy

Go to download

Google Collections Library is a suite of new collections and collection-related goodness for Java 5.0

The newest version!
/*
 * 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 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. * * @author Mike Bostock * @author Jared Levy */ 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, 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(); } } 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: * *

Collection<E> s = Synchronized.collection(
   *      new HashSet<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 mutex) { return new SynchronizedCollection(collection, mutex); } /** @see Synchronized#collection */ static class SynchronizedCollection extends SynchronizedObject implements Collection { public SynchronizedCollection(Collection delegate, 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 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: * *

Set<E> s = Synchronized.set(new HashSet<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 mutex) { return new SynchronizedSet(set, mutex); } /** @see Synchronized#set */ static class SynchronizedSet extends SynchronizedCollection implements Set { public SynchronizedSet(Set delegate, 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: * *

SortedSet<E> s = Synchronized.sortedSet(
   *      new TreeSet<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 mutex) { return new SynchronizedSortedSet(set, mutex); } /** @see Synchronized#sortedSet */ static class SynchronizedSortedSet extends SynchronizedSet implements SortedSet { public SynchronizedSortedSet(SortedSet delegate, Object mutex) { super(delegate, mutex); } @Override protected SortedSet delegate() { return (SortedSet) super.delegate(); } public Comparator 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: * *

List<E> l = Synchronized.list(new ArrayList<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 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, 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 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); } } public List subList(int fromIndex, int toIndex) { synchronized (mutex) { return list(delegate().subList(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, 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: * *

Multiset<E> s = Synchronized.multiset(
   *      new HashMultiset<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 mutex) { return new SynchronizedMultiset(multiset, mutex); } /** @see Synchronized#multiset */ static class SynchronizedMultiset extends SynchronizedCollection implements Multiset { private transient volatile Set elementSet; private transient volatile Set> entrySet; public SynchronizedMultiset(Multiset delegate, 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 boolean 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 removeAllOccurrences(Object o) { synchronized (mutex) { return delegate().removeAllOccurrences(o); } } 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: * *

Multimap<K,V> m = Synchronized.multimap(
   *      new HashMultimap<K,V>(), mutex);
   *   ...
   *  Set<K> s = m.keySet();  // Needn't be in synchronized block
   *   ...
   *  synchronized (mutex) {
   *    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 mutex) { return new SynchronizedMultimap(multimap, mutex); } /** @see Synchronized#multimap */ private static class SynchronizedMultimap extends SynchronizedObject implements Multimap { transient volatile Set keySet; transient volatile Collection valuesCollection; transient volatile Collection> entries; transient volatile Map> asMap; transient volatile Multiset keys; @SuppressWarnings("unchecked") @Override protected Multimap delegate() { return (Multimap) super.delegate(); } SynchronizedMultimap(Multimap delegate, 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 void putAll(K key, Iterable values) { synchronized (mutex) { delegate().putAll(key, values); } } public void putAll(Multimap multimap) { synchronized (mutex) { delegate().putAll(multimap); } } public Collection replaceValues(K key, Iterable 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, Object mutex) { return new SynchronizedListMultimap(multimap, mutex); } /** @see Synchronized#listMultimap */ private static class SynchronizedListMultimap extends SynchronizedMultimap implements ListMultimap { SynchronizedListMultimap(ListMultimap delegate, 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 list(delegate().removeAll(key), mutex); } } @Override public List replaceValues( K key, Iterable values) { synchronized (mutex) { return list(delegate().replaceValues(key, values), mutex); } } 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, Object mutex) { return new SynchronizedSetMultimap(multimap, mutex); } /** @see Synchronized#setMultimap */ private static class SynchronizedSetMultimap extends SynchronizedMultimap implements SetMultimap { SynchronizedSetMultimap(SetMultimap delegate, 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 set(delegate().removeAll(key), mutex); } } @Override public Set replaceValues( K key, Iterable values) { synchronized (mutex) { return set(delegate().replaceValues(key, values), mutex); } } @Override public Set> entries() { synchronized (mutex) { return set(delegate().entries(), mutex); } } 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, Object mutex) { return new SynchronizedSortedSetMultimap(multimap, mutex); } /** @see Synchronized#sortedSetMultimap */ private static class SynchronizedSortedSetMultimap extends SynchronizedSetMultimap implements SortedSetMultimap { SynchronizedSortedSetMultimap( SortedSetMultimap delegate, 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 sortedSet(delegate().removeAll(key), mutex); } } @Override public SortedSet replaceValues( K key, Iterable values) { synchronized (mutex) { return sortedSet(delegate().replaceValues(key, values), mutex); } } public Comparator 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: * *

Collection<E> s = Synchronized.typePreservingCollection(
   *      new HashSet<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 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: * *

Set<E> s = Synchronized.typePreservingSet(
   *      new HashSet<E>(), mutex);
   *   ...
   * synchronized (mutex) {
   *   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 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, Object mutex) { super(delegate, mutex); } @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(), mutex); } }; } }; } // See Collections.CheckedEntrySet for details on attacks. @Override public Object[] toArray() { synchronized (mutex) { return ForwardingCollection.toArrayImpl(delegate()); } } @Override public T[] toArray(T[] array) { synchronized (mutex) { return ForwardingCollection.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 ForwardingCollection.containsAllImpl(delegate(), c); } } @Override public boolean equals(Object o) { if (o == this) { return true; } synchronized (mutex) { return ForwardingSet.equalsImpl(delegate(), o); } } @Override public boolean remove(Object o) { synchronized (mutex) { return Maps.removeEntryImpl(delegate(), o); } } @Override public boolean removeAll(Collection c) { synchronized (mutex) { return ForwardingCollection.removeAllImpl(delegate(), c); } } @Override public boolean retainAll(Collection c) { synchronized (mutex) { return ForwardingCollection.retainAllImpl(delegate(), 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: * *

Map<K,V> m = Synchronized.map(
   *      new HashMap<K,V>(), mutex);
   *   ...
   *  Set<K> s = m.keySet();  // Needn't be in synchronized block
   *   ...
   *  synchronized (mutex) {
   *    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 mutex) { return new SynchronizedMap(map, mutex); } /** @see Synchronized#map */ static class SynchronizedMap extends SynchronizedObject implements Map { private transient volatile Set keySet; private transient volatile Collection values; private transient volatile Set> entrySet; public SynchronizedMap(Map delegate, 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 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 String toString() { synchronized (mutex) { return delegate().toString(); } } @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: * *

BiMap<K,V> m = Synchronized.biMap(
   *      new HashBiMap<K,V>(), mutex);
   *   ...
   *  Set<K> s = m.keySet();  // Needn't be in synchronized block
   *   ...
   *  synchronized (mutex) {
   *    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 mutex) { return new SynchronizedBiMap(bimap, mutex, null); } /** @see Synchronized#biMap */ static class SynchronizedBiMap extends SynchronizedMap implements BiMap, Serializable { private transient volatile Set valueSet; private transient volatile BiMap inverse; public SynchronizedBiMap( BiMap delegate, Object mutex, 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 volatile Set>> asMapEntrySet; private transient volatile Collection> asMapValues; public SynchronizedAsMap(Map> delegate, 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() { if (asMapEntrySet == null) { asMapEntrySet = new SynchronizedAsMapEntries( delegate().entrySet(), mutex); } return asMapEntrySet; } @Override public Collection> values() { if (asMapValues == null) { asMapValues = new SynchronizedAsMapValues(delegate().values(), mutex); } return asMapValues; } @Override public boolean containsValue(Object o) { return values().contains(o); } private static final long serialVersionUID = 0; } /** @see SynchronizedMultimap#asMap */ static class SynchronizedAsMapValues extends SynchronizedCollection> { SynchronizedAsMapValues(Collection> delegate, Object mutex) { super(delegate, mutex); } @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(), mutex); } }; } // See Collections.CheckedEntrySet for details on attacks. @Override public Object[] toArray() { synchronized (mutex) { return ForwardingCollection.toArrayImpl(delegate()); } } @Override public T[] toArray(T[] array) { synchronized (mutex) { return ForwardingCollection.toArrayImpl(delegate(), array); } } @Override public boolean contains(Object o) { synchronized (mutex) { return ForwardingCollection.containsImpl(delegate(), o); } } @Override public boolean containsAll(Collection c) { synchronized (mutex) { return ForwardingCollection.containsAllImpl(delegate(), c); } } @Override public boolean remove(Object o) { synchronized (mutex) { return ForwardingCollection.removeImpl(delegate(), o); } } @Override public boolean removeAll(Collection c) { synchronized (mutex) { return ForwardingCollection.removeAllImpl(delegate(), c); } } @Override public boolean retainAll(Collection c) { synchronized (mutex) { return ForwardingCollection.retainAllImpl(delegate(), c); } } private static final long serialVersionUID = 0; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy