001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.util.concurrent; 018 019import static com.google.common.base.Preconditions.checkNotNull; 020 021import com.google.common.annotations.GwtCompatible; 022import com.google.common.annotations.J2ktIncompatible; 023import com.google.errorprone.annotations.CanIgnoreReturnValue; 024import java.io.Serializable; 025import java.util.Collections; 026import java.util.Map; 027import java.util.concurrent.ConcurrentHashMap; 028import java.util.concurrent.atomic.AtomicBoolean; 029import java.util.concurrent.atomic.AtomicLong; 030import java.util.function.LongBinaryOperator; 031import java.util.function.LongUnaryOperator; 032import javax.annotation.CheckForNull; 033 034/** 035 * A map containing {@code long} values that can be atomically updated. While writes to a 036 * traditional {@code Map} rely on {@code put(K, V)}, the typical mechanism for writing to this map 037 * is {@code addAndGet(K, long)}, which adds a {@code long} to the value currently associated with 038 * {@code K}. If a key has not yet been associated with a value, its implicit value is zero. 039 * 040 * <p>Most methods in this class treat absent values and zero values identically, as individually 041 * documented. Exceptions to this are {@link #containsKey}, {@link #size}, {@link #isEmpty}, {@link 042 * #asMap}, and {@link #toString}. 043 * 044 * <p>Instances of this class may be used by multiple threads concurrently. All operations are 045 * atomic unless otherwise noted. 046 * 047 * <p>Instances of this class are serializable if the keys are serializable. 048 * 049 * <p><b>Note:</b> If your values are always positive and less than 2^31, you may wish to use a 050 * {@link com.google.common.collect.Multiset} such as {@link 051 * com.google.common.collect.ConcurrentHashMultiset} instead. 052 * 053 * <p><b>Warning:</b> Unlike {@code Multiset}, entries whose values are zero are not automatically 054 * removed from the map. Instead they must be removed manually with {@link #removeAllZeros}. 055 * 056 * @author Charles Fry 057 * @since 11.0 058 */ 059@GwtCompatible 060@J2ktIncompatible 061@ElementTypesAreNonnullByDefault 062public final class AtomicLongMap<K> implements Serializable { 063 private final ConcurrentHashMap<K, Long> map; 064 065 private AtomicLongMap(ConcurrentHashMap<K, Long> map) { 066 this.map = checkNotNull(map); 067 } 068 069 /** Creates an {@code AtomicLongMap}. */ 070 public static <K> AtomicLongMap<K> create() { 071 return new AtomicLongMap<K>(new ConcurrentHashMap<>()); 072 } 073 074 /** Creates an {@code AtomicLongMap} with the same mappings as the specified {@code Map}. */ 075 public static <K> AtomicLongMap<K> create(Map<? extends K, ? extends Long> m) { 076 AtomicLongMap<K> result = create(); 077 result.putAll(m); 078 return result; 079 } 080 081 /** 082 * Returns the value associated with {@code key}, or zero if there is no value associated with 083 * {@code key}. 084 */ 085 public long get(K key) { 086 return map.getOrDefault(key, 0L); 087 } 088 089 /** 090 * Increments by one the value currently associated with {@code key}, and returns the new value. 091 */ 092 @CanIgnoreReturnValue 093 public long incrementAndGet(K key) { 094 return addAndGet(key, 1); 095 } 096 097 /** 098 * Decrements by one the value currently associated with {@code key}, and returns the new value. 099 */ 100 @CanIgnoreReturnValue 101 public long decrementAndGet(K key) { 102 return addAndGet(key, -1); 103 } 104 105 /** 106 * Adds {@code delta} to the value currently associated with {@code key}, and returns the new 107 * value. 108 */ 109 @CanIgnoreReturnValue 110 public long addAndGet(K key, long delta) { 111 return accumulateAndGet(key, delta, Long::sum); 112 } 113 114 /** 115 * Increments by one the value currently associated with {@code key}, and returns the old value. 116 */ 117 @CanIgnoreReturnValue 118 public long getAndIncrement(K key) { 119 return getAndAdd(key, 1); 120 } 121 122 /** 123 * Decrements by one the value currently associated with {@code key}, and returns the old value. 124 */ 125 @CanIgnoreReturnValue 126 public long getAndDecrement(K key) { 127 return getAndAdd(key, -1); 128 } 129 130 /** 131 * Adds {@code delta} to the value currently associated with {@code key}, and returns the old 132 * value. 133 */ 134 @CanIgnoreReturnValue 135 public long getAndAdd(K key, long delta) { 136 return getAndAccumulate(key, delta, Long::sum); 137 } 138 139 /** 140 * Updates the value currently associated with {@code key} with the specified function, and 141 * returns the new value. If there is not currently a value associated with {@code key}, the 142 * function is applied to {@code 0L}. 143 * 144 * @since 21.0 145 */ 146 @CanIgnoreReturnValue 147 public long updateAndGet(K key, LongUnaryOperator updaterFunction) { 148 checkNotNull(updaterFunction); 149 return map.compute( 150 key, (k, value) -> updaterFunction.applyAsLong((value == null) ? 0L : value.longValue())); 151 } 152 153 /** 154 * Updates the value currently associated with {@code key} with the specified function, and 155 * returns the old value. If there is not currently a value associated with {@code key}, the 156 * function is applied to {@code 0L}. 157 * 158 * @since 21.0 159 */ 160 @CanIgnoreReturnValue 161 public long getAndUpdate(K key, LongUnaryOperator updaterFunction) { 162 checkNotNull(updaterFunction); 163 AtomicLong holder = new AtomicLong(); 164 map.compute( 165 key, 166 (k, value) -> { 167 long oldValue = (value == null) ? 0L : value.longValue(); 168 holder.set(oldValue); 169 return updaterFunction.applyAsLong(oldValue); 170 }); 171 return holder.get(); 172 } 173 174 /** 175 * Updates the value currently associated with {@code key} by combining it with {@code x} via the 176 * specified accumulator function, returning the new value. The previous value associated with 177 * {@code key} (or zero, if there is none) is passed as the first argument to {@code 178 * accumulatorFunction}, and {@code x} is passed as the second argument. 179 * 180 * @since 21.0 181 */ 182 @CanIgnoreReturnValue 183 public long accumulateAndGet(K key, long x, LongBinaryOperator accumulatorFunction) { 184 checkNotNull(accumulatorFunction); 185 return updateAndGet(key, oldValue -> accumulatorFunction.applyAsLong(oldValue, x)); 186 } 187 188 /** 189 * Updates the value currently associated with {@code key} by combining it with {@code x} via the 190 * specified accumulator function, returning the old value. The previous value associated with 191 * {@code key} (or zero, if there is none) is passed as the first argument to {@code 192 * accumulatorFunction}, and {@code x} is passed as the second argument. 193 * 194 * @since 21.0 195 */ 196 @CanIgnoreReturnValue 197 public long getAndAccumulate(K key, long x, LongBinaryOperator accumulatorFunction) { 198 checkNotNull(accumulatorFunction); 199 return getAndUpdate(key, oldValue -> accumulatorFunction.applyAsLong(oldValue, x)); 200 } 201 202 /** 203 * Associates {@code newValue} with {@code key} in this map, and returns the value previously 204 * associated with {@code key}, or zero if there was no such value. 205 */ 206 @CanIgnoreReturnValue 207 public long put(K key, long newValue) { 208 return getAndUpdate(key, x -> newValue); 209 } 210 211 /** 212 * Copies all of the mappings from the specified map to this map. The effect of this call is 213 * equivalent to that of calling {@code put(k, v)} on this map once for each mapping from key 214 * {@code k} to value {@code v} in the specified map. The behavior of this operation is undefined 215 * if the specified map is modified while the operation is in progress. 216 */ 217 public void putAll(Map<? extends K, ? extends Long> m) { 218 m.forEach(this::put); 219 } 220 221 /** 222 * Removes and returns the value associated with {@code key}. If {@code key} is not in the map, 223 * this method has no effect and returns zero. 224 */ 225 @CanIgnoreReturnValue 226 public long remove(K key) { 227 Long result = map.remove(key); 228 return (result == null) ? 0L : result.longValue(); 229 } 230 231 /** 232 * If {@code (key, value)} is currently in the map, this method removes it and returns true; 233 * otherwise, this method returns false. 234 */ 235 boolean remove(K key, long value) { 236 return map.remove(key, value); 237 } 238 239 /** 240 * Atomically remove {@code key} from the map iff its associated value is 0. 241 * 242 * @since 20.0 243 */ 244 @CanIgnoreReturnValue 245 public boolean removeIfZero(K key) { 246 return remove(key, 0); 247 } 248 249 /** 250 * Removes all mappings from this map whose values are zero. 251 * 252 * <p>This method is not atomic: the map may be visible in intermediate states, where some of the 253 * zero values have been removed and others have not. 254 */ 255 public void removeAllZeros() { 256 map.values().removeIf(x -> x == 0); 257 } 258 259 /** 260 * Returns the sum of all values in this map. 261 * 262 * <p>This method is not atomic: the sum may or may not include other concurrent operations. 263 */ 264 public long sum() { 265 return map.values().stream().mapToLong(Long::longValue).sum(); 266 } 267 268 @CheckForNull private transient Map<K, Long> asMap; 269 270 /** Returns a live, read-only view of the map backing this {@code AtomicLongMap}. */ 271 public Map<K, Long> asMap() { 272 Map<K, Long> result = asMap; 273 return (result == null) ? asMap = createAsMap() : result; 274 } 275 276 private Map<K, Long> createAsMap() { 277 return Collections.unmodifiableMap(map); 278 } 279 280 /** Returns true if this map contains a mapping for the specified key. */ 281 public boolean containsKey(Object key) { 282 return map.containsKey(key); 283 } 284 285 /** 286 * Returns the number of key-value mappings in this map. If the map contains more than {@code 287 * Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}. 288 */ 289 public int size() { 290 return map.size(); 291 } 292 293 /** Returns {@code true} if this map contains no key-value mappings. */ 294 public boolean isEmpty() { 295 return map.isEmpty(); 296 } 297 298 /** 299 * Removes all of the mappings from this map. The map will be empty after this call returns. 300 * 301 * <p>This method is not atomic: the map may not be empty after returning if there were concurrent 302 * writes. 303 */ 304 public void clear() { 305 map.clear(); 306 } 307 308 @Override 309 public String toString() { 310 return map.toString(); 311 } 312 313 /** 314 * If {@code key} is not already associated with a value or if {@code key} is associated with 315 * zero, associate it with {@code newValue}. Returns the previous value associated with {@code 316 * key}, or zero if there was no mapping for {@code key}. 317 */ 318 long putIfAbsent(K key, long newValue) { 319 AtomicBoolean noValue = new AtomicBoolean(false); 320 Long result = 321 map.compute( 322 key, 323 (k, oldValue) -> { 324 if (oldValue == null || oldValue == 0) { 325 noValue.set(true); 326 return newValue; 327 } else { 328 return oldValue; 329 } 330 }); 331 return noValue.get() ? 0L : result.longValue(); 332 } 333 334 /** 335 * If {@code (key, expectedOldValue)} is currently in the map, this method replaces {@code 336 * expectedOldValue} with {@code newValue} and returns true; otherwise, this method returns false. 337 * 338 * <p>If {@code expectedOldValue} is zero, this method will succeed if {@code (key, zero)} is 339 * currently in the map, or if {@code key} is not in the map at all. 340 */ 341 boolean replace(K key, long expectedOldValue, long newValue) { 342 if (expectedOldValue == 0L) { 343 return putIfAbsent(key, newValue) == 0L; 344 } else { 345 return map.replace(key, expectedOldValue, newValue); 346 } 347 } 348}