View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.collections4.collection;
19  
20  import java.io.Serializable;
21  import java.util.Collection;
22  import java.util.Iterator;
23  import java.util.Objects;
24  import java.util.function.Consumer;
25  import java.util.function.Predicate;
26  
27  /**
28   * Decorates another {@link Collection} to synchronize its behavior for a multithreaded environment.
29   * <p>
30   * Iterators must be manually synchronized:
31   * </p>
32   *
33   * <pre>
34   * synchronized (coll) {
35   *     Iterator it = coll.iterator();
36   *     // do stuff with iterator
37   * }
38   * </pre>
39   * <p>
40   * This class is Serializable from Commons Collections 3.1.
41   * </p>
42   *
43   * @param <E> The type of the elements in the collection.
44   * @since 3.0
45   */
46  public class SynchronizedCollection<E> implements Collection<E>, Serializable {
47  
48      /** Serialization version */
49      private static final long serialVersionUID = 2412805092710877986L;
50  
51      /**
52       * Creates a synchronized collection.
53       *
54       * @param <T>  The type of the elements in the collection.
55       * @param coll The collection to decorate, must not be null.
56       * @return A new synchronized collection.
57       * @throws NullPointerException if collection is null.
58       * @since 4.0
59       */
60      public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) {
61          return new SynchronizedCollection<>(coll);
62      }
63  
64      /** The collection to decorate */
65      private final Collection<E> collection;
66  
67      /** The object to lock on, needed for List/SortedSet views */
68      protected final Object lock;
69  
70      /**
71       * Constructs and wraps (not copies).
72       *
73       * @param collection The collection to decorate, must not be null.
74       * @throws NullPointerException if the collection is null.
75       */
76      protected SynchronizedCollection(final Collection<E> collection) {
77          this.collection = Objects.requireNonNull(collection, "collection");
78          this.lock = this;
79      }
80  
81      /**
82       * Constructs and wraps (not copies).
83       *
84       * @param collection The collection to decorate, must not be null.
85       * @param lock       The lock object to use, must not be null.
86       * @throws NullPointerException if the collection or lock is null.
87       */
88      protected SynchronizedCollection(final Collection<E> collection, final Object lock) {
89          this.collection = Objects.requireNonNull(collection, "collection");
90          this.lock = Objects.requireNonNull(lock, "lock");
91      }
92  
93      @Override
94      public boolean add(final E object) {
95          synchronized (lock) {
96              return decorated().add(object);
97          }
98      }
99  
100     @Override
101     public boolean addAll(final Collection<? extends E> coll) {
102         synchronized (lock) {
103             return decorated().addAll(coll);
104         }
105     }
106 
107     @Override
108     public void clear() {
109         synchronized (lock) {
110             decorated().clear();
111         }
112     }
113 
114     @Override
115     public boolean contains(final Object object) {
116         synchronized (lock) {
117             return decorated().contains(object);
118         }
119     }
120 
121     @Override
122     public boolean containsAll(final Collection<?> coll) {
123         synchronized (lock) {
124             return decorated().containsAll(coll);
125         }
126     }
127 
128     /**
129      * Gets the collection being decorated.
130      *
131      * @return The decorated collection.
132      */
133     protected Collection<E> decorated() {
134         return collection;
135     }
136 
137     @Override
138     public boolean equals(final Object object) {
139         synchronized (lock) {
140             if (object == this) {
141                 return true;
142             }
143             return object == this || decorated().equals(object);
144         }
145     }
146 
147     /**
148      * @since 4.6.0
149      */
150     @Override
151     public void forEach(final Consumer<? super E> action) {
152         synchronized (lock) {
153             decorated().forEach(action);
154         }
155     }
156 
157     @Override
158     public int hashCode() {
159         synchronized (lock) {
160             return decorated().hashCode();
161         }
162     }
163 
164     @Override
165     public boolean isEmpty() {
166         synchronized (lock) {
167             return decorated().isEmpty();
168         }
169     }
170 
171     /**
172      * Iterators must be manually synchronized.
173      *
174      * <pre>
175      * synchronized (coll) {
176      *     Iterator it = coll.iterator();
177      *     // do stuff with iterator
178      * }
179      * </pre>
180      *
181      * @return An iterator that must be manually synchronized on the collection.
182      */
183     @Override
184     public Iterator<E> iterator() {
185         return decorated().iterator();
186     }
187 
188     @Override
189     public boolean remove(final Object object) {
190         synchronized (lock) {
191             return decorated().remove(object);
192         }
193     }
194 
195     @Override
196     public boolean removeAll(final Collection<?> coll) {
197         synchronized (lock) {
198             return decorated().removeAll(coll);
199         }
200     }
201 
202     /**
203      * @since 4.4
204      */
205     @Override
206     public boolean removeIf(final Predicate<? super E> filter) {
207         synchronized (lock) {
208             return decorated().removeIf(filter);
209         }
210     }
211 
212     @Override
213     public boolean retainAll(final Collection<?> coll) {
214         synchronized (lock) {
215             return decorated().retainAll(coll);
216         }
217     }
218 
219     @Override
220     public int size() {
221         synchronized (lock) {
222             return decorated().size();
223         }
224     }
225 
226     @Override
227     public Object[] toArray() {
228         synchronized (lock) {
229             return decorated().toArray();
230         }
231     }
232 
233     @Override
234     public <T> T[] toArray(final T[] object) {
235         synchronized (lock) {
236             return decorated().toArray(object);
237         }
238     }
239 
240     @Override
241     public String toString() {
242         synchronized (lock) {
243             return decorated().toString();
244         }
245     }
246 }