diff --git a/NOTICE.txt b/NOTICE.txt index a5369e791..97b38fd63 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -3,3 +3,7 @@ Copyright 2001-2024 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (https://www.apache.org/). + +The Java source file src/main/java/org/apache/commons/collections4/map/ConcurrentReferenceHashMap.java +is from https://github.com/hazelcast/hazelcast and the following notice applies: +Copyright (c) 2008-2020, Hazelcast, Inc. All Rights Reserved. diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cb39c1d33..b30019ee5 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -44,6 +44,7 @@ Add TreeBag.TreeBag(Iterable). Add CartesianProductIterator #509. Add missing methods in AbstractMapTests. + Add ConcurrentReferenceHashMap. Update bloom filter documentation #508. Bump commons-codec:commons-codec from 1.17.0 to 1.17.1 #514. diff --git a/src/main/java/org/apache/commons/collections4/map/ConcurrentReferenceHashMap.java b/src/main/java/org/apache/commons/collections4/map/ConcurrentReferenceHashMap.java new file mode 100644 index 000000000..74739d7b8 --- /dev/null +++ b/src/main/java/org/apache/commons/collections4/map/ConcurrentReferenceHashMap.java @@ -0,0 +1,1885 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* + * Copyright (c) 2008-2020, Hazelcast, Inc. All Rights Reserved. + */ + +package org.apache.commons.collections4.map; + +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.EnumSet; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * An advanced hash map supporting configurable garbage collection semantics of keys and values, optional referential-equality, full concurrency of retrievals, + * and adjustable expected concurrency for updates. + *

+ * This map is designed around specific advanced use-cases. If there is any doubt whether this map is for you, you most likely should be using + * {@link java.util.concurrent.ConcurrentHashMap} instead. + *

+ *

+ * This map supports strong, weak, and soft keys and values. By default, keys are weak, and values are strong. Such a configuration offers similar behavior to + * {@link java.util.WeakHashMap}, entries of this map are periodically removed once their corresponding keys are no longer referenced outside of this map. In + * other words, this map will not prevent a key from being discarded by the garbage collector. Once a key has been discarded by the collector, the corresponding + * entry is no longer visible to this map; however, the entry may occupy space until a future map operation decides to reclaim it. For this reason, summary + * functions such as {@code size} and {@code isEmpty} might return a value greater than the observed number of entries. In order to support a high level of + * concurrency, stale entries are only reclaimed during blocking (usually mutating) operations. + *

+ *

+ * Enabling soft keys allows entries in this map to remain until their space is absolutely needed by the garbage collector. This is unlike weak keys which can + * be reclaimed as soon as they are no longer referenced by a normal strong reference. The primary use case for soft keys is a cache, which ideally occupies + * memory that is not in use for as long as possible. + *

+ *

+ * By default, values are held using a normal strong reference. This provides the commonly desired guarantee that a value will always have at least the same + * life-span as its key. For this reason, care should be taken to ensure that a value never refers, either directly or indirectly, to its key, thereby + * preventing reclamation. If this is unavoidable, then it is recommended to use the same reference type in use for the key. However, it should be noted that + * non-strong values may disappear before their corresponding key. + *

+ *

+ * While this map does allow the use of both strong keys and values, it is recommended you use {@link java.util.concurrent.ConcurrentHashMap} for such a + * configuration, since it is optimized for that case. + *

+ *

+ * Just like {@link java.util.concurrent.ConcurrentHashMap}, this class obeys the same functional specification as {@link Hashtable}, and includes versions of + * methods corresponding to each method of {@code Hashtable}. However, even though all operations are thread-safe, retrieval operations do not entail + * locking, and there is not any support for locking the entire map in a way that prevents all access. This class is fully interoperable with + * {@code Hashtable} in programs that rely on its thread safety but not on its synchronization details. + *

+ *

+ * Retrieval operations (including {@code get}) generally do not block, so they may overlap with update operations (including {@code put} and {@code remove}). + * Retrievals reflect the results of the most recently completed update operations holding upon their onset. For aggregate operations such as + * {@code putAll} and {@code clear}, concurrent retrievals may reflect insertion or removal of only some entries. Similarly, Iterators and Enumerations return + * elements reflecting the state of the hash map at some point at or since the creation of the iterator/enumeration. They do not throw + * {@link ConcurrentModificationException}. However, iterators are designed to be used by only one thread at a time. + *

+ *

+ * The allowed concurrency among update operations is guided by the optional {@code concurrencyLevel} constructor argument (default + * {@value #DEFAULT_CONCURRENCY_LEVEL}), which is used as a hint for internal sizing. The map is internally partitioned to try to permit the indicated number of + * concurrent updates without contention. Because placement in hash tables is essentially random, the actual concurrency will vary. Ideally, you should choose a + * value to accommodate as many threads as will ever concurrently modify the map. Using a significantly higher value than you need can waste space and time, and + * a significantly lower value can lead to thread contention. But overestimates and underestimates within an order of magnitude do not usually have much + * noticeable impact. A value of one is appropriate when it is known that only one thread will modify and all others will only read. Also, resizing this or any + * other kind of hash map is a relatively slow operation, so, when possible, it is a good idea that you provide estimates of expected map sizes in constructors. + *

+ *

+ * This class and its views and iterators implement all of the optional methods of the {@link Map} and {@link Iterator} interfaces. + *

+ *

+ * Like {@link Hashtable} but unlike {@link HashMap}, this class does not allow {@code null} to be used as a key or value. + *

+ *

+ * Provenance: Copied and edited from Apache Groovy git master at commit 77dc80a7512ceb2168b1bc866c3d0c69b002fe11; via Doug Lea, Jason T. Greene, with + * assistance from members of JCP JSR-166, and Hazelcast. + *

+ * + * @param the type of keys maintained by this map. + * @param the type of mapped values. + */ +public class ConcurrentReferenceHashMap extends AbstractMap implements ConcurrentMap { + + /** + * Builds new ConcurrentReferenceHashMap instances. + *

+ * By default, keys are weak, and values are strong. + *

+ *

+ * The default values are: + *

+ *
    + *
  • concurrency level: {@value #DEFAULT_CONCURRENCY_LEVEL}
  • + *
  • initial capacity: {@value #DEFAULT_INITIAL_CAPACITY}
  • + *
  • key reference type: {@link ReferenceType#WEAK}
  • + *
  • load factor: {@value #DEFAULT_LOAD_FACTOR}
  • + *
  • options: {@code null}
  • + *
  • source map: {@code null}
  • + *
  • value reference type: {@link ReferenceType#STRONG}
  • + *
+ * + * @param the type of keys. + * @param the type of values. + */ + public static class Builder implements Supplier> { + + private static final Map DEFAULT_SOURCE_MAP = null; + + private int initialCapacity = DEFAULT_INITIAL_CAPACITY; + private float loadFactor = DEFAULT_LOAD_FACTOR; + private int concurrencyLevel = DEFAULT_CONCURRENCY_LEVEL; + private ReferenceType keyReferenceType = DEFAULT_KEY_TYPE; + private ReferenceType valueReferenceType = DEFAULT_VALUE_TYPE; + private EnumSet