implement ConcurrentHashMap and AtomicReferenceArray

This is the simplest possible ConcurrentHashMap I could come up with
that works and is actually concurrent in the way one would expect.
It's pretty unconventional, being based on a persistent red-black
tree, and not particularly memory-efficient or cache-friendly.  I
think this is a good place to start, though, and it should perform
reasonably well for most workloads.  Patches for a more efficient
implementation are welcome!

I also implemented AtomicReferenceArray, since I was using it in my
first, naive attempt to implement ConcurrentHashMap.

I had to do a bit of refactoring, including moving some non-standard
stuff from java.util.Collections to avian.Data so I could make it
available to code outside the java.util package, which is why I had to
modify several unrelated files.
This commit is contained in:
Joel Dice
2014-03-07 09:08:19 -07:00
parent b6c3bc6f4d
commit c0d178d5f1
19 changed files with 1074 additions and 284 deletions

View File

@ -10,6 +10,8 @@
package java.util;
import avian.Data;
public class HashMap<K, V> implements Map<K, V> {
private static final int MinimumCapacity = 16;
@ -19,7 +21,7 @@ public class HashMap<K, V> implements Map<K, V> {
public HashMap(int capacity, Helper<K, V> helper) {
if (capacity > 0) {
array = new Cell[nextPowerOfTwo(capacity)];
array = new Cell[Data.nextPowerOfTwo(capacity)];
}
this.helper = helper;
}
@ -40,13 +42,7 @@ public class HashMap<K, V> implements Map<K, V> {
}
public String toString() {
return Collections.toString(this);
}
private static int nextPowerOfTwo(int n) {
int r = 1;
while (r < n) r <<= 1;
return r;
return avian.Data.toString(this);
}
public boolean isEmpty() {
@ -72,7 +68,7 @@ public class HashMap<K, V> implements Map<K, V> {
private void resize(int capacity) {
Cell<K, V>[] newArray = null;
if (capacity != 0) {
capacity = nextPowerOfTwo(capacity);
capacity = Data.nextPowerOfTwo(capacity);
if (array != null && array.length == capacity) {
return;
}
@ -220,21 +216,43 @@ public class HashMap<K, V> implements Map<K, V> {
}
public Set<Entry<K, V>> entrySet() {
return new EntrySet();
return new Data.EntrySet(new MyEntryMap());
}
public Set<K> keySet() {
return new KeySet();
return new Data.KeySet(new MyEntryMap());
}
public Collection<V> values() {
return new Values();
return new Data.Values(new MyEntryMap());
}
Iterator<Entry<K, V>> iterator() {
return new MyIterator();
}
private class MyEntryMap implements Data.EntryMap<K, V> {
public int size() {
return HashMap.this.size();
}
public Entry<K,V> find(Object key) {
return HashMap.this.find(key);
}
public Entry<K,V> remove(Object key) {
return removeCell(key);
}
public void clear() {
HashMap.this.clear();
}
public Iterator<Entry<K,V>> iterator() {
return HashMap.this.iterator();
}
}
interface Cell<K, V> extends Entry<K, V> {
public HashMap.Cell<K, V> next();
@ -303,148 +321,6 @@ public class HashMap<K, V> implements Map<K, V> {
}
}
private class EntrySet extends AbstractSet<Entry<K, V>> {
public int size() {
return HashMap.this.size();
}
public boolean isEmpty() {
return HashMap.this.isEmpty();
}
public boolean contains(Object o) {
return (o instanceof Entry<?,?>)
&& containsKey(((Entry<?,?>)o).getKey());
}
public boolean add(Entry<K, V> e) {
return putCell(e.getKey(), e.getValue()) != null;
}
public boolean remove(Object o) {
return (o instanceof Entry<?,?>) && remove((Entry<?,?>)o);
}
public boolean remove(Entry<K, V> e) {
return removeCell(e.getKey()) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
public void clear() {
HashMap.this.clear();
}
public Iterator<Entry<K, V>> iterator() {
return new MyIterator();
}
}
private class KeySet extends AbstractSet<K> {
public int size() {
return HashMap.this.size();
}
public boolean isEmpty() {
return HashMap.this.isEmpty();
}
public boolean contains(Object key) {
return containsKey(key);
}
public boolean add(K key) {
return putCell(key, null) != null;
}
public boolean remove(Object key) {
return removeCell(key) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
public void clear() {
HashMap.this.clear();
}
public Iterator<K> iterator() {
return new Collections.KeyIterator(new MyIterator());
}
}
private class Values implements Collection<V> {
public int size() {
return HashMap.this.size();
}
public boolean isEmpty() {
return HashMap.this.isEmpty();
}
public boolean contains(Object value) {
return containsValue(value);
}
public boolean containsAll(Collection<?> c) {
if (c == null) {
throw new NullPointerException("collection is null");
}
Iterator<?> it = c.iterator();
while (it.hasNext()) {
if (! contains(it.next())) {
return false;
}
}
return true;
}
public boolean add(V value) {
throw new UnsupportedOperationException();
}
public boolean addAll(Collection<? extends V> collection) {
throw new UnsupportedOperationException();
}
public boolean remove(Object value) {
throw new UnsupportedOperationException();
}
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
public void clear() {
HashMap.this.clear();
}
public Iterator<V> iterator() {
return new Collections.ValueIterator(new MyIterator());
}
}
private class MyIterator implements Iterator<Entry<K, V>> {
private int currentIndex = -1;
private int nextIndex = -1;