001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.collection; 018 019import java.io.Serializable; 020import java.util.Collection; 021import java.util.Iterator; 022 023/** 024 * Decorates another {@link Collection} to synchronize its behaviour 025 * for a multi-threaded environment. 026 * <p> 027 * Iterators must be manually synchronized: 028 * <pre> 029 * synchronized (coll) { 030 * Iterator it = coll.iterator(); 031 * // do stuff with iterator 032 * } 033 * </pre> 034 * <p> 035 * This class is Serializable from Commons Collections 3.1. 036 * 037 * @param <E> the type of the elements in the collection 038 * @since 3.0 039 */ 040public class SynchronizedCollection<E> implements Collection<E>, Serializable { 041 042 /** Serialization version */ 043 private static final long serialVersionUID = 2412805092710877986L; 044 045 /** The collection to decorate */ 046 private final Collection<E> collection; 047 /** The object to lock on, needed for List/SortedSet views */ 048 protected final Object lock; 049 050 /** 051 * Factory method to create a synchronized collection. 052 * 053 * @param <T> the type of the elements in the collection 054 * @param coll the collection to decorate, must not be null 055 * @return a new synchronized collection 056 * @throws NullPointerException if collection is null 057 * @since 4.0 058 */ 059 public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) { 060 return new SynchronizedCollection<>(coll); 061 } 062 063 //----------------------------------------------------------------------- 064 /** 065 * Constructor that wraps (not copies). 066 * 067 * @param collection the collection to decorate, must not be null 068 * @throws NullPointerException if the collection is null 069 */ 070 protected SynchronizedCollection(final Collection<E> collection) { 071 if (collection == null) { 072 throw new NullPointerException("Collection must not be null."); 073 } 074 this.collection = collection; 075 this.lock = this; 076 } 077 078 /** 079 * Constructor that wraps (not copies). 080 * 081 * @param collection the collection to decorate, must not be null 082 * @param lock the lock object to use, must not be null 083 * @throws NullPointerException if the collection or lock is null 084 */ 085 protected SynchronizedCollection(final Collection<E> collection, final Object lock) { 086 if (collection == null) { 087 throw new NullPointerException("Collection must not be null."); 088 } 089 if (lock == null) { 090 throw new NullPointerException("Lock must not be null."); 091 } 092 this.collection = collection; 093 this.lock = lock; 094 } 095 096 /** 097 * Gets the collection being decorated. 098 * 099 * @return the decorated collection 100 */ 101 protected Collection<E> decorated() { 102 return collection; 103 } 104 105 //----------------------------------------------------------------------- 106 107 @Override 108 public boolean add(final E object) { 109 synchronized (lock) { 110 return decorated().add(object); 111 } 112 } 113 114 @Override 115 public boolean addAll(final Collection<? extends E> coll) { 116 synchronized (lock) { 117 return decorated().addAll(coll); 118 } 119 } 120 121 @Override 122 public void clear() { 123 synchronized (lock) { 124 decorated().clear(); 125 } 126 } 127 128 @Override 129 public boolean contains(final Object object) { 130 synchronized (lock) { 131 return decorated().contains(object); 132 } 133 } 134 135 @Override 136 public boolean containsAll(final Collection<?> coll) { 137 synchronized (lock) { 138 return decorated().containsAll(coll); 139 } 140 } 141 142 @Override 143 public boolean isEmpty() { 144 synchronized (lock) { 145 return decorated().isEmpty(); 146 } 147 } 148 149 /** 150 * Iterators must be manually synchronized. 151 * <pre> 152 * synchronized (coll) { 153 * Iterator it = coll.iterator(); 154 * // do stuff with iterator 155 * } 156 * </pre> 157 * 158 * @return an iterator that must be manually synchronized on the collection 159 */ 160 @Override 161 public Iterator<E> iterator() { 162 return decorated().iterator(); 163 } 164 165 @Override 166 public Object[] toArray() { 167 synchronized (lock) { 168 return decorated().toArray(); 169 } 170 } 171 172 @Override 173 public <T> T[] toArray(final T[] object) { 174 synchronized (lock) { 175 return decorated().toArray(object); 176 } 177 } 178 179 @Override 180 public boolean remove(final Object object) { 181 synchronized (lock) { 182 return decorated().remove(object); 183 } 184 } 185 186 @Override 187 public boolean removeAll(final Collection<?> coll) { 188 synchronized (lock) { 189 return decorated().removeAll(coll); 190 } 191 } 192 193 @Override 194 public boolean retainAll(final Collection<?> coll) { 195 synchronized (lock) { 196 return decorated().retainAll(coll); 197 } 198 } 199 200 @Override 201 public int size() { 202 synchronized (lock) { 203 return decorated().size(); 204 } 205 } 206 207 @Override 208 public boolean equals(final Object object) { 209 synchronized (lock) { 210 if (object == this) { 211 return true; 212 } 213 return object == this || decorated().equals(object); 214 } 215 } 216 217 @Override 218 public int hashCode() { 219 synchronized (lock) { 220 return decorated().hashCode(); 221 } 222 } 223 224 @Override 225 public String toString() { 226 synchronized (lock) { 227 return decorated().toString(); 228 } 229 } 230 231}