mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
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:
parent
b6c3bc6f4d
commit
c0d178d5f1
310
classpath/avian/Data.java
Normal file
310
classpath/avian/Data.java
Normal file
@ -0,0 +1,310 @@
|
||||
/* Copyright (c) 2008-2014, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
|
||||
public class Data {
|
||||
public static int nextPowerOfTwo(int n) {
|
||||
int r = 1;
|
||||
while (r < n) r <<= 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <V> boolean equal(V a, V b) {
|
||||
return a == null ? b == null : a.equals(b);
|
||||
}
|
||||
|
||||
public static <T> T[] toArray(Collection collection, T[] array) {
|
||||
Class c = array.getClass().getComponentType();
|
||||
|
||||
if (array.length < collection.size()) {
|
||||
array = (T[]) java.lang.reflect.Array.newInstance(c, collection.size());
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Object o: collection) {
|
||||
if (c.isInstance(o)) {
|
||||
array[i++] = (T) o;
|
||||
} else {
|
||||
throw new ArrayStoreException();
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static String toString(Collection c) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||
sb.append(it.next());
|
||||
if (it.hasNext()) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String toString(Map m) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
for (Iterator<Entry> it = m.entrySet().iterator(); it.hasNext();) {
|
||||
Entry e = it.next();
|
||||
sb.append(e.getKey())
|
||||
.append("=")
|
||||
.append(e.getValue());
|
||||
if (it.hasNext()) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public interface EntryMap<K,V> {
|
||||
public int size();
|
||||
|
||||
public Entry<K,V> find(Object key);
|
||||
|
||||
public Entry<K,V> remove(Object key);
|
||||
|
||||
public void clear();
|
||||
|
||||
public Iterator<Entry<K,V>> iterator();
|
||||
}
|
||||
|
||||
public static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> {
|
||||
private final EntryMap<K, V> map;
|
||||
|
||||
public EntrySet(EntryMap<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.size() == 0;
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return (o instanceof Entry<?,?>)
|
||||
&& map.find(((Entry<?,?>)o).getKey()) != null;
|
||||
}
|
||||
|
||||
public boolean add(Entry<K, V> e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
return (o instanceof Entry<?,?>)
|
||||
&& map.remove(((Entry<?,?>) o).getKey()) != null;
|
||||
}
|
||||
|
||||
public boolean remove(Entry<K, V> e) {
|
||||
return map.remove(e.getKey()) != null;
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[size()]);
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return map.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeySet<K> extends AbstractSet<K> {
|
||||
private final EntryMap<K, ?> map;
|
||||
|
||||
public KeySet(EntryMap<K, ?> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.size() == 0;
|
||||
}
|
||||
|
||||
public boolean contains(Object key) {
|
||||
return map.find(key) != null;
|
||||
}
|
||||
|
||||
public boolean add(K key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean remove(Object key) {
|
||||
return map.remove(key) != null;
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[size()]);
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public Iterator<K> iterator() {
|
||||
return new KeyIterator(map.iterator());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Values<K, V> implements Collection<V> {
|
||||
private final EntryMap<K, V> map;
|
||||
|
||||
public Values(EntryMap<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.size() == 0;
|
||||
}
|
||||
|
||||
public boolean contains(Object value) {
|
||||
for (Iterator<Entry<K, V>> it = map.iterator(); it.hasNext();) {
|
||||
if (equal(it.next().getValue(), value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
if (c == null) {
|
||||
throw new NullPointerException("collection is null");
|
||||
}
|
||||
|
||||
for (Iterator<?> it = c.iterator(); 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) {
|
||||
for (Iterator<Entry<K, V>> it = map.iterator();
|
||||
it.hasNext();)
|
||||
{
|
||||
if (equal(it.next().getValue(), value)) {
|
||||
it.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
boolean changed = false;
|
||||
for (Iterator<Entry<K, V>> it = map.iterator(); it.hasNext();) {
|
||||
if (c.contains(it.next().getValue())) {
|
||||
it.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return toArray(new Object[size()]);
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public Iterator<V> iterator() {
|
||||
return new ValueIterator(map.iterator());
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeyIterator<K, V> implements Iterator<K> {
|
||||
private final Iterator<Entry<K, V>> it;
|
||||
|
||||
public KeyIterator(Iterator<Entry<K, V>> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public K next() {
|
||||
return it.next().getKey();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ValueIterator<K, V> implements Iterator<V> {
|
||||
private final Iterator<Entry<K, V>> it;
|
||||
|
||||
public ValueIterator(Iterator<Entry<K, V>> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public V next() {
|
||||
return it.next().getValue();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
@ -97,12 +97,12 @@ public abstract class AbstractCollection<T> implements Collection<T> {
|
||||
}
|
||||
|
||||
public <S> S[] toArray(S[] array) {
|
||||
return Collections.toArray(this, array);
|
||||
return avian.Data.toArray(this, array);
|
||||
}
|
||||
|
||||
public abstract Iterator<T> iterator();
|
||||
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ public class ArrayList<T> extends AbstractList<T> implements java.io.Serializabl
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
|
@ -10,12 +10,14 @@
|
||||
|
||||
package java.util;
|
||||
|
||||
import avian.Data;
|
||||
|
||||
public class Collections {
|
||||
|
||||
private Collections() { }
|
||||
|
||||
public static void shuffle(List list, Random random) {
|
||||
Object[] array = toArray(list, new Object[list.size()]);
|
||||
Object[] array = Data.toArray(list, new Object[list.size()]);
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
int j = random.nextInt(array.length);
|
||||
Object tmp = array[i];
|
||||
@ -173,25 +175,6 @@ public class Collections {
|
||||
}
|
||||
}
|
||||
|
||||
static <T> T[] toArray(Collection collection, T[] array) {
|
||||
Class c = array.getClass().getComponentType();
|
||||
|
||||
if (array.length < collection.size()) {
|
||||
array = (T[]) java.lang.reflect.Array.newInstance(c, collection.size());
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Object o: collection) {
|
||||
if (c.isInstance(o)) {
|
||||
array[i++] = (T) o;
|
||||
} else {
|
||||
throw new ArrayStoreException();
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static final List EMPTY_LIST
|
||||
= new UnmodifiableList<Object>(new ArrayList<Object>(0));
|
||||
|
||||
@ -208,35 +191,6 @@ public class Collections {
|
||||
return (Set<T>) new UnmodifiableSet<Object>(
|
||||
new HashSet<Object>(0));
|
||||
}
|
||||
|
||||
static String toString(Collection c) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||
sb.append(it.next());
|
||||
if (it.hasNext()) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static String toString(Map m) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
for (Iterator<Map.Entry> it = m.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry e = it.next();
|
||||
sb.append(e.getKey())
|
||||
.append("=")
|
||||
.append(e.getValue());
|
||||
if (it.hasNext()) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static <T> Enumeration<T> enumeration(Collection<T> c) {
|
||||
return new IteratorEnumeration<T> (c.iterator());
|
||||
@ -746,46 +700,6 @@ public class Collections {
|
||||
public static <T> Set<T> unmodifiableSet(Set<T> hs) {
|
||||
return new UnmodifiableSet<T>(hs);
|
||||
}
|
||||
|
||||
static class KeyIterator<K, V> implements Iterator<K> {
|
||||
private final Iterator<Map.Entry<K, V>> it;
|
||||
|
||||
public KeyIterator(Iterator<Map.Entry<K, V>> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public K next() {
|
||||
return it.next().getKey();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
static class ValueIterator<K, V> implements Iterator<V> {
|
||||
private final Iterator<Map.Entry<K, V>> it;
|
||||
|
||||
public ValueIterator(Iterator<Map.Entry<K, V>> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public V next() {
|
||||
return it.next().getValue();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ReverseComparator<T> implements Comparator<T> {
|
||||
|
||||
|
@ -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;
|
||||
|
@ -63,7 +63,7 @@ public class HashSet<T> extends AbstractSet<T> implements Set<T> {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
|
||||
private static class MyIterator<T> implements Iterator<T> {
|
||||
|
@ -131,7 +131,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Collections.toArray(this, array);
|
||||
return avian.Data.toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -169,7 +169,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Collections.toArray(this, array);
|
||||
return avian.Data.toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -177,7 +177,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
||||
}
|
||||
|
||||
public Iterator<K> iterator() {
|
||||
return new Collections.KeyIterator(new MyIterator());
|
||||
return new avian.Data.KeyIterator(new MyIterator());
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Collections.toArray(this, array);
|
||||
return avian.Data.toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -238,7 +238,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
||||
}
|
||||
|
||||
public Iterator<V> iterator() {
|
||||
return new Collections.ValueIterator(new MyIterator());
|
||||
return new avian.Data.ValueIterator(new MyIterator());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ public class LinkedHashSet<T> extends AbstractSet<T> implements Set<T> {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
|
||||
private static class MyIterator<T> implements Iterator<T> {
|
||||
|
@ -360,7 +360,7 @@ public class LinkedList<T> extends AbstractSequentialList<T> implements Deque<T>
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,7 +42,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
|
||||
public V get(Object key) {
|
||||
@ -164,7 +164,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Collections.toArray(this, array);
|
||||
return avian.Data.toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -172,7 +172,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
||||
}
|
||||
|
||||
public Iterator<K> iterator() {
|
||||
return new Collections.KeyIterator(set.iterator());
|
||||
return new avian.Data.KeyIterator(set.iterator());
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Collections.toArray(this, array);
|
||||
return avian.Data.toArray(this, array);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -233,7 +233,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
||||
}
|
||||
|
||||
public Iterator<V> iterator() {
|
||||
return new Collections.ValueIterator(set.iterator());
|
||||
return new avian.Data.ValueIterator(set.iterator());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Collections.toString(this);
|
||||
return avian.Data.toString(this);
|
||||
}
|
||||
|
||||
public boolean add(T value) {
|
||||
|
430
classpath/java/util/concurrent/ConcurrentHashMap.java
Normal file
430
classpath/java/util/concurrent/ConcurrentHashMap.java
Normal file
@ -0,0 +1,430 @@
|
||||
/* Copyright (c) 2008-2014, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import avian.Data;
|
||||
import avian.PersistentSet;
|
||||
import avian.PersistentSet.Path;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class ConcurrentHashMap<K,V>
|
||||
extends AbstractMap<K,V>
|
||||
implements ConcurrentMap<K,V>
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final long Content;
|
||||
private static final Content Empty = new Content(new PersistentSet(), 0);
|
||||
|
||||
static {
|
||||
try {
|
||||
Content = unsafe.objectFieldOffset
|
||||
(ConcurrentHashMap.class.getDeclaredField("content"));
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private volatile Content<K,V> content;
|
||||
|
||||
public ConcurrentHashMap() {
|
||||
content = Empty;
|
||||
}
|
||||
|
||||
public ConcurrentHashMap(int initialCapacity) {
|
||||
this();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return content.size == 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return content.size;
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
return find(key) != null;
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
for (V v: values()) {
|
||||
if (value.equals(v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public V get(Object key) {
|
||||
Cell<K,V> cell = find(key);
|
||||
return cell == null ? null : cell.value;
|
||||
}
|
||||
|
||||
private Cell<K,V> find(Object key) {
|
||||
Content<K,V> c = content;
|
||||
|
||||
Path<Node<Cell<K,V>>> path = c.set.find(new Node(key.hashCode()));
|
||||
for (Cell<K,V> cell = path.value().value;
|
||||
cell != null;
|
||||
cell = cell.next)
|
||||
{
|
||||
if (key.equals(cell.key)) {
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public V putIfAbsent(K key, V value) {
|
||||
Cell<K,V> cell = put(key, value, PutCondition.IfAbsent, null);
|
||||
return cell == null ? null : cell.value;
|
||||
}
|
||||
|
||||
public boolean remove(K key, V value) {
|
||||
Cell<K,V> cell = remove(key, RemoveCondition.IfEqual, value);
|
||||
return cell != null && cell.value.equals(value);
|
||||
}
|
||||
|
||||
public V replace(K key, V value) {
|
||||
Cell<K,V> cell = put(key, value, PutCondition.IfPresent, null);
|
||||
return cell == null ? null : cell.value;
|
||||
}
|
||||
|
||||
public boolean replace(K key, V oldValue, V newValue) {
|
||||
Cell<K,V> cell = put(key, newValue, PutCondition.IfEqual, oldValue);
|
||||
return cell != null && cell.value.equals(oldValue);
|
||||
}
|
||||
|
||||
public V put(K key, V value) {
|
||||
Cell<K,V> cell = put(key, value, PutCondition.Always, null);
|
||||
return cell == null ? null : cell.value;
|
||||
}
|
||||
|
||||
public V remove(Object key) {
|
||||
Cell<K,V> cell = remove(key, RemoveCondition.Always, null);
|
||||
return cell == null ? null : cell.value;
|
||||
}
|
||||
|
||||
private enum PutCondition {
|
||||
Always() {
|
||||
public boolean addIfAbsent() { return true; }
|
||||
public <V> boolean addIfPresent(V a, V b) { return true; }
|
||||
}, IfAbsent() {
|
||||
public boolean addIfAbsent() { return true; }
|
||||
public <V> boolean addIfPresent(V a, V b) { return false; }
|
||||
}, IfPresent() {
|
||||
public boolean addIfAbsent() { return false; }
|
||||
public <V> boolean addIfPresent(V a, V b) { return true; }
|
||||
}, IfEqual() {
|
||||
public boolean addIfAbsent() { return false; }
|
||||
public <V> boolean addIfPresent(V a, V b) { return a.equals(b); }
|
||||
};
|
||||
|
||||
public boolean addIfAbsent() { throw new AssertionError(); }
|
||||
public <V> boolean addIfPresent(V a, V b) { throw new AssertionError(); }
|
||||
}
|
||||
|
||||
private enum RemoveCondition {
|
||||
Always() {
|
||||
public <V> boolean remove(V a, V b) { return true; }
|
||||
}, IfEqual() {
|
||||
public <V> boolean remove(V a, V b) { return a.equals(b); }
|
||||
};
|
||||
|
||||
public <V> boolean remove(V a, V b) { throw new AssertionError(); }
|
||||
}
|
||||
|
||||
private Cell<K,V> put(K key, V value, PutCondition condition, V oldValue) {
|
||||
Node<Cell<K,V>> node = new Node(key.hashCode());
|
||||
|
||||
loop: while (true) {
|
||||
node.value = null;
|
||||
Content content = this.content;
|
||||
Path<Node<Cell<K,V>>> path = content.set.find(node);
|
||||
for (Cell<K,V> cell = path.value().value;
|
||||
cell != null;
|
||||
cell = cell.next)
|
||||
{
|
||||
if (key.equals(cell.key)) {
|
||||
if (! condition.addIfPresent(cell.value, oldValue)) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
Cell<K,V> start = null;
|
||||
Cell<K,V> last = null;
|
||||
for (Cell<K,V> cell2 = path.value().value;
|
||||
true;
|
||||
cell2 = cell2.next)
|
||||
{
|
||||
Cell<K,V> c;
|
||||
c = cell2.clone();
|
||||
|
||||
if (last == null) {
|
||||
last = start = c;
|
||||
} else {
|
||||
last.next = c;
|
||||
last = c;
|
||||
}
|
||||
|
||||
if (cell2 == cell) {
|
||||
c.value = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node.value = start;
|
||||
if (unsafe.compareAndSwapObject
|
||||
(this, Content, content, new Content
|
||||
(path.replaceWith(node), content.size)))
|
||||
{
|
||||
return cell;
|
||||
} else {
|
||||
continue loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no mapping found -- add a new one if appropriate
|
||||
if (! condition.addIfAbsent()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
node.value = new Cell(key, value, null);
|
||||
if (unsafe.compareAndSwapObject
|
||||
(this, Content, content, new Content
|
||||
(path.fresh() ? path.add() : path.replaceWith(node),
|
||||
content.size + 1)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
for (Map.Entry<? extends K, ? extends V> e: map.entrySet()) {
|
||||
put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Cell<K,V> remove(Object key, RemoveCondition condition,
|
||||
V oldValue)
|
||||
{
|
||||
Node<Cell<K,V>> node = new Node(key.hashCode());
|
||||
|
||||
loop: while (true) {
|
||||
node.value = null;
|
||||
Content content = this.content;
|
||||
Path<Node<Cell<K,V>>> path = content.set.find(node);
|
||||
for (Cell<K,V> cell = path.value().value;
|
||||
cell != null;
|
||||
cell = cell.next)
|
||||
{
|
||||
if (key.equals(cell.key)) {
|
||||
if (! condition.remove(cell.value, oldValue)) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
Cell<K,V> start = null;
|
||||
Cell<K,V> last = null;
|
||||
for (Cell<K,V> cell2 = path.value().value;
|
||||
cell2 != cell;
|
||||
cell2 = cell2.next)
|
||||
{
|
||||
Cell<K,V> c = cell2.clone();
|
||||
if (last == null) {
|
||||
last = start = c;
|
||||
} else {
|
||||
last.next = c;
|
||||
last = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (last == null) {
|
||||
start = last = cell.next;
|
||||
} else {
|
||||
last.next = cell.next;
|
||||
}
|
||||
|
||||
node.value = start;
|
||||
if (unsafe.compareAndSwapObject
|
||||
(this, Content, content, new Content
|
||||
(start == null ? path.remove() : path.replaceWith(node),
|
||||
content.size - 1)))
|
||||
{
|
||||
return cell;
|
||||
} else {
|
||||
continue loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
content = Empty;
|
||||
}
|
||||
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
return new Data.EntrySet(new MyEntryMap());
|
||||
}
|
||||
|
||||
public Set<K> keySet() {
|
||||
return new Data.KeySet(new MyEntryMap());
|
||||
}
|
||||
|
||||
public Collection<V> values() {
|
||||
return new Data.Values(new MyEntryMap());
|
||||
}
|
||||
|
||||
private class MyEntryMap implements Data.EntryMap<K, V> {
|
||||
public int size() {
|
||||
return ConcurrentHashMap.this.size();
|
||||
}
|
||||
|
||||
public Map.Entry<K,V> find(Object key) {
|
||||
return new MyEntry(ConcurrentHashMap.this.find(key));
|
||||
}
|
||||
|
||||
public Map.Entry<K,V> remove(Object key) {
|
||||
return new MyEntry
|
||||
(ConcurrentHashMap.this.remove(key, RemoveCondition.Always, null));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ConcurrentHashMap.this.clear();
|
||||
}
|
||||
|
||||
public Iterator<Map.Entry<K,V>> iterator() {
|
||||
return new MyIterator(content);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Content<K,V> {
|
||||
private final PersistentSet<Node<Cell<K,V>>> set;
|
||||
private final int size;
|
||||
|
||||
public Content(PersistentSet<Node<Cell<K,V>>> set,
|
||||
int size)
|
||||
{
|
||||
this.set = set;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Cell<K,V> implements Cloneable {
|
||||
public final K key;
|
||||
public V value;
|
||||
public Cell<K,V> next;
|
||||
|
||||
public Cell(K key, V value, Cell<K,V> next) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public Cell<K,V> clone() {
|
||||
try {
|
||||
return (Cell<K,V>) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Node<T> implements Comparable<Node<T>> {
|
||||
public final int key;
|
||||
public T value;
|
||||
|
||||
public Node(int key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public int compareTo(Node<T> n) {
|
||||
return key - n.key;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyEntry implements Map.Entry<K,V> {
|
||||
private final K key;
|
||||
private V value;
|
||||
|
||||
public MyEntry(Cell<K,V> cell) {
|
||||
key = cell.key;
|
||||
value = cell.value;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public V setValue(V value) {
|
||||
V v = value;
|
||||
this.value = value;
|
||||
put(key, value);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyIterator implements Iterator<Map.Entry<K, V>> {
|
||||
private final Content<K,V> content;
|
||||
private final Iterator<Node<Cell<K, V>>> iterator;
|
||||
private Cell<K, V> currentCell;
|
||||
private Cell<K, V> nextCell;
|
||||
|
||||
public MyIterator(Content<K,V> content) {
|
||||
this.content = content;
|
||||
this.iterator = content.set.iterator();
|
||||
hasNext();
|
||||
}
|
||||
|
||||
public Map.Entry<K, V> next() {
|
||||
if (hasNext()) {
|
||||
currentCell = nextCell;
|
||||
|
||||
nextCell = nextCell.next;
|
||||
|
||||
return new MyEntry(currentCell);
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
if (nextCell == null && iterator.hasNext()) {
|
||||
nextCell = iterator.next().value;
|
||||
}
|
||||
return nextCell != null;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (currentCell != null) {
|
||||
ConcurrentHashMap.this.remove
|
||||
(currentCell.key, RemoveCondition.Always, null);
|
||||
currentCell = null;
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
classpath/java/util/concurrent/ConcurrentMap.java
Normal file
23
classpath/java/util/concurrent/ConcurrentMap.java
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright (c) 2008-2014, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ConcurrentMap<K,V> extends Map<K,V> {
|
||||
public V putIfAbsent(K key, V value);
|
||||
|
||||
public boolean remove(K key, V value);
|
||||
|
||||
public V replace(K key, V value);
|
||||
|
||||
public boolean replace(K key, V oldValue, V newValue);
|
||||
}
|
@ -32,9 +32,9 @@ public class AtomicReference<T> implements java.io.Serializable {
|
||||
public T get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public void set(T newValue) {
|
||||
this.value = newValue;
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
public void lazySet(T newValue) {
|
||||
|
@ -0,0 +1,69 @@
|
||||
/* Copyright (c) 2008-2014, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.concurrent.atomic;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
public class AtomicReferenceArray<T> {
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final long arrayOffset = unsafe.arrayBaseOffset(Object.class);
|
||||
private static final long arrayScale = unsafe.arrayIndexScale(Object.class);
|
||||
|
||||
private final Object[] array;
|
||||
|
||||
public AtomicReferenceArray(int length) {
|
||||
array = new Object[length];
|
||||
}
|
||||
|
||||
public T get(int index) {
|
||||
return (T) unsafe.getObjectVolatile
|
||||
(array, arrayOffset + (index * arrayScale));
|
||||
}
|
||||
|
||||
public void set(int index, T newValue) {
|
||||
unsafe.putObjectVolatile
|
||||
(array, arrayOffset + (index * arrayScale), newValue);
|
||||
}
|
||||
|
||||
public void lazySet(int index, T newValue) {
|
||||
unsafe.putOrderedObject
|
||||
(array, arrayOffset + (index * arrayScale), newValue);
|
||||
}
|
||||
|
||||
public boolean compareAndSet(int index, T expect, T update) {
|
||||
return unsafe.compareAndSwapObject
|
||||
(array, arrayOffset + (index * arrayScale), expect, update);
|
||||
}
|
||||
|
||||
public boolean weakCompareAndSet(int index, T expect, T update) {
|
||||
return compareAndSet(index, expect, update);
|
||||
}
|
||||
|
||||
public final T getAndSet(int index, T newValue) {
|
||||
while (true) {
|
||||
T current = get(index);
|
||||
if (compareAndSet(index, current, newValue)) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Arrays.toString(array);
|
||||
}
|
||||
}
|
@ -74,6 +74,8 @@ public final class Unsafe {
|
||||
|
||||
public native int arrayBaseOffset(Class arrayClass);
|
||||
|
||||
public native int arrayIndexScale(Class arrayClass);
|
||||
|
||||
public native long objectFieldOffset(Field field);
|
||||
|
||||
public native void park(boolean absolute, long time);
|
||||
|
@ -663,6 +663,28 @@ Avian_sun_misc_Unsafe_arrayBaseOffset
|
||||
return ArrayBody;
|
||||
}
|
||||
|
||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||
Avian_sun_misc_Unsafe_arrayIndexScale
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object c = jclassVmClass(t, reinterpret_cast<object>(arguments[1]));
|
||||
|
||||
if (c == type(t, Machine::JbooleanType)
|
||||
|| c == type(t, Machine::JbyteType))
|
||||
return 1;
|
||||
else if (c == type(t, Machine::JshortType)
|
||||
|| c == type(t, Machine::JcharType))
|
||||
return 2;
|
||||
else if (c == type(t, Machine::JintType)
|
||||
|| c == type(t, Machine::JfloatType))
|
||||
return 4;
|
||||
else if (c == type(t, Machine::JlongType)
|
||||
|| c == type(t, Machine::JdoubleType))
|
||||
return 8;
|
||||
else
|
||||
return BytesPerWord;
|
||||
}
|
||||
|
||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||
Avian_java_nio_FixedArrayByteBuffer_allocateFixed
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
|
@ -2558,28 +2558,6 @@ Avian_sun_misc_Unsafe_staticFieldOffset
|
||||
(t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)));
|
||||
}
|
||||
|
||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||
Avian_sun_misc_Unsafe_arrayIndexScale
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
switch (byteArrayBody
|
||||
(t, className
|
||||
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[1]))), 1))
|
||||
{
|
||||
case 'Z':
|
||||
case 'B': return 1;
|
||||
case 'S':
|
||||
case 'C': return 2;
|
||||
case 'I':
|
||||
case 'F': return 4;
|
||||
case 'J':
|
||||
case 'D': return 8;
|
||||
case '[':
|
||||
case 'L': return BytesPerWord;
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||
Avian_sun_misc_Unsafe_staticFieldBase
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
|
166
test/Concurrent.java
Normal file
166
test/Concurrent.java
Normal file
@ -0,0 +1,166 @@
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class Concurrent {
|
||||
private static final int ThreadCount = 4;
|
||||
private static final int IterationCount = 100;
|
||||
private static final int Range = 10;
|
||||
private static final int CommonBase = -Range;
|
||||
|
||||
private static void expect(boolean v) {
|
||||
if (! v) throw new RuntimeException();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
final ConcurrentMap<Integer, Object> map = new ConcurrentHashMap();
|
||||
final int[] counter = new int[1];
|
||||
final int[] step = new int[1];
|
||||
final Throwable[] exception = new Throwable[1];
|
||||
|
||||
synchronized (map) {
|
||||
for (int i = 0; i < ThreadCount; ++i) {
|
||||
final int index = i;
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (map) {
|
||||
++ counter[0];
|
||||
map.notifyAll();
|
||||
while (exception[0] == null && step[0] == 0) {
|
||||
map.wait();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < IterationCount; ++i) {
|
||||
populateCommon(map);
|
||||
populate(map, index * Range);
|
||||
}
|
||||
|
||||
synchronized (map) {
|
||||
-- counter[0];
|
||||
map.notifyAll();
|
||||
while (exception[0] == null && step[0] == 1) {
|
||||
map.wait();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < IterationCount; ++i) {
|
||||
populate(map, index * Range);
|
||||
depopulate(map, index * Range);
|
||||
}
|
||||
|
||||
synchronized (map) {
|
||||
++ counter[0];
|
||||
map.notifyAll();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
synchronized (map) {
|
||||
exception[0] = e;
|
||||
map.notifyAll();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
try {
|
||||
while (exception[0] == null && counter[0] < ThreadCount) {
|
||||
map.wait();
|
||||
}
|
||||
|
||||
step[0] = 1;
|
||||
map.notifyAll();
|
||||
|
||||
while (exception[0] == null && counter[0] > 0) {
|
||||
map.wait();
|
||||
}
|
||||
|
||||
if (map.size() != ThreadCount * Range) {
|
||||
System.err.println
|
||||
("expected " + (ThreadCount * Range) + " got " + map.size());
|
||||
}
|
||||
expect(map.size() == ThreadCount * Range);
|
||||
for (int i = CommonBase, j = CommonBase + Range; i < j; ++i) {
|
||||
expect(! map.containsKey(i));
|
||||
}
|
||||
|
||||
step[0] = 2;
|
||||
map.notifyAll();
|
||||
|
||||
while (exception[0] == null && counter[0] < ThreadCount) {
|
||||
map.wait();
|
||||
}
|
||||
|
||||
expect(map.isEmpty());
|
||||
expect(exception[0] == null);
|
||||
} catch (Throwable e) {
|
||||
exception[0] = e;
|
||||
throw e;
|
||||
} finally {
|
||||
map.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void populateCommon(ConcurrentMap<Integer, Object> map) {
|
||||
Object value = new Object();
|
||||
for (int i = CommonBase, j = CommonBase + Range; i < j; ++i) {
|
||||
map.remove(i);
|
||||
map.put(i, value);
|
||||
map.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void populate(ConcurrentMap<Integer, Object> map, int base) {
|
||||
for (int i = base, j = base + Range; i < j; ++i) {
|
||||
map.remove(i);
|
||||
Object value = new Object();
|
||||
expect(map.put(i, value) == null);
|
||||
expect(map.containsKey(i));
|
||||
expect(map.get(i).equals(value));
|
||||
expect(map.putIfAbsent(i, new Object()) == value);
|
||||
expect(map.get(i).equals(value));
|
||||
expect(! map.remove(i, new Object()));
|
||||
expect(map.remove(i, value));
|
||||
expect(map.replace(i, value) == null);
|
||||
expect(! map.containsKey(i));
|
||||
expect(map.get(i) == null);
|
||||
expect(map.putIfAbsent(i, value) == null);
|
||||
expect(map.containsKey(i));
|
||||
expect(map.get(i) == value);
|
||||
Object newValue = new Object();
|
||||
expect(map.replace(i, newValue) == value);
|
||||
expect(map.get(i) == newValue);
|
||||
|
||||
boolean found = false;
|
||||
for (Iterator<Map.Entry<Integer, Object>> it = map.entrySet().iterator();
|
||||
it.hasNext();)
|
||||
{
|
||||
Map.Entry<Integer, Object> e = it.next();
|
||||
if (e.getKey() == i) {
|
||||
expect(! found);
|
||||
expect(e.getValue() == newValue);
|
||||
found = true;
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
expect(found);
|
||||
expect(! map.containsKey(i));
|
||||
expect(map.putIfAbsent(i, value) == null);
|
||||
expect(map.containsKey(i));
|
||||
expect(map.get(i) == value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void depopulate(ConcurrentMap<Integer, Object> map, int base)
|
||||
{
|
||||
for (int i = base, j = base + Range; i < j; ++i) {
|
||||
expect(map.containsKey(i));
|
||||
expect(map.remove(i) != null);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user