Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -101,7 +105,17 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
/**
* Late binding entry set.
*/
private volatile @Nullable Set<Map.Entry<K, V>> entrySet;
private @Nullable Set<Map.Entry<K, V>> entrySet;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remove volatile here, and didn't make the new fields volatile, since this is just a benign race; ConcurrentHashMap does the same thing. Seems preferable to paying the cost of the volatile field access.


/**
* Late binding key set.
*/
private @Nullable Set<K> keySet;

/**
* Late binding values collection.
*/
private @Nullable Collection<V> values;


/**
Expand Down Expand Up @@ -512,6 +526,26 @@ public Set<Map.Entry<K, V>> entrySet() {
return entrySet;
}

@Override
public Set<K> keySet() {
Set<K> keySet = this.keySet;
if (keySet == null) {
keySet = new KeySet();
this.keySet = keySet;
}
return keySet;
}

@Override
public Collection<V> values() {
Collection<V> values = this.values;
if (values == null) {
values = new Values();
this.values = values;
}
return values;
}

private <T> @Nullable T doTask(@Nullable Object key, Task<T> task) {
int hash = getHash(key);
return getSegmentForHash(hash).doTask(hash, key, task);
Expand Down Expand Up @@ -940,7 +974,7 @@ private interface Entries<V> {
/**
* Internal entry-set implementation.
*/
private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
private final class EntrySet extends AbstractSet<Map.Entry<K, V>> {

@Override
public Iterator<Map.Entry<K, V>> iterator() {
Expand Down Expand Up @@ -976,13 +1010,133 @@ public int size() {
public void clear() {
ConcurrentReferenceHashMap.this.clear();
}

@Override
public Spliterator<Map.Entry<K, V>> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.CONCURRENT);
}
}

/**
* Internal key-set implementation.
*/
private final class KeySet extends AbstractSet<K> {
@Override
public Iterator<K> iterator() {
return new KeyIterator();
}

@Override
public int size() {
return ConcurrentReferenceHashMap.this.size();
}

@Override
public boolean isEmpty() {
return ConcurrentReferenceHashMap.this.isEmpty();
}

@Override
public void clear() {
ConcurrentReferenceHashMap.this.clear();
}

@Override
public boolean contains(Object k) {
return ConcurrentReferenceHashMap.this.containsKey(k);
}

@Override
public Spliterator<K> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.CONCURRENT);
}
}

/**
* Internal key iterator implementation.
*/
private final class KeyIterator implements Iterator<K> {

private final Iterator<Map.Entry<K, V>> iterator = entrySet().iterator();

@Override
public boolean hasNext() {
return this.iterator.hasNext();
}

@Override
public void remove() {
this.iterator.remove();
}

@Override
public K next() {
return this.iterator.next().getKey();
}
}

/**
* Internal values collection implementation.
*/
private final class Values extends AbstractCollection<V> {
@Override
public Iterator<V> iterator() {
return new ValueIterator();
}

@Override
public int size() {
return ConcurrentReferenceHashMap.this.size();
}

@Override
public boolean isEmpty() {
return ConcurrentReferenceHashMap.this.isEmpty();
}

@Override
public void clear() {
ConcurrentReferenceHashMap.this.clear();
}

@Override
public boolean contains(Object v) {
return ConcurrentReferenceHashMap.this.containsValue(v);
}

@Override
public Spliterator<V> spliterator() {
return Spliterators.spliterator(this, Spliterator.CONCURRENT);
}
}

/**
* Internal value iterator implementation.
*/
private final class ValueIterator implements Iterator<V> {

private final Iterator<Map.Entry<K, V>> iterator = entrySet().iterator();

@Override
public boolean hasNext() {
return this.iterator.hasNext();
}

@Override
public void remove() {
this.iterator.remove();
}

@Override
public V next() {
return this.iterator.next().getValue();
}
}

/**
* Internal entry iterator implementation.
*/
private class EntryIterator implements Iterator<Map.Entry<K, V>> {
private final class EntryIterator implements Iterator<Map.Entry<K, V>> {

private int segmentIndex;

Expand Down
Loading