📄 concurrentreaderhashmap.java
字号:
first = new Entry(e.hash, e.key, e.value, first);
ttab[i] = first;
}
return t;
}
catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
// Views
protected transient Set keySet = null;
protected transient Set entrySet = null;
protected transient Collection values = null;
/**
* Returns a set view of the keys contained in this map. The set is
* backed by the map, so changes to the map are reflected in the set, and
* vice-versa. The set supports element removal, which removes the
* corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
* <tt>clear</tt> operations. It does not support the <tt>add</tt> or
* <tt>addAll</tt> operations.
*
* @return a set view of the keys contained in this map.
*/
public Set keySet() {
Set ks = keySet;
return (ks != null)? ks : (keySet = new KeySet());
}
private class KeySet extends AbstractSet {
public Iterator iterator() {
return new KeyIterator();
}
public int size() {
return ConcurrentReaderHashMap.this.size();
}
public boolean contains(Object o) {
return ConcurrentReaderHashMap.this.containsKey(o);
}
public boolean remove(Object o) {
return ConcurrentReaderHashMap.this.remove(o) != null;
}
public void clear() {
ConcurrentReaderHashMap.this.clear();
}
}
/**
* Returns a collection view of the values contained in this map. The
* collection is backed by the map, so changes to the map are reflected in
* the collection, and vice-versa. The collection supports element
* removal, which removes the corresponding mapping from this map, via the
* <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
* It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
*
* @return a collection view of the values contained in this map.
*/
public Collection values() {
Collection vs = values;
return (vs != null)? vs : (values = new Values());
}
private class Values extends AbstractCollection {
public Iterator iterator() {
return new ValueIterator();
}
public int size() {
return ConcurrentReaderHashMap.this.size();
}
public boolean contains(Object o) {
return ConcurrentReaderHashMap.this.containsValue(o);
}
public void clear() {
ConcurrentReaderHashMap.this.clear();
}
}
/**
* Returns a collection view of the mappings contained in this map. Each
* element in the returned collection is a <tt>Map.Entry</tt>. The
* collection is backed by the map, so changes to the map are reflected in
* the collection, and vice-versa. The collection supports element
* removal, which removes the corresponding mapping from the map, via the
* <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
* It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
*
* @return a collection view of the mappings contained in this map.
*/
public Set entrySet() {
Set es = entrySet;
return (es != null) ? es : (entrySet = new EntrySet());
}
private class EntrySet extends AbstractSet {
public Iterator iterator() {
return new HashIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry entry = (Map.Entry)o;
Object v = ConcurrentReaderHashMap.this.get(entry.getKey());
return v != null && v.equals(entry.getValue());
}
public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
return ConcurrentReaderHashMap.this.findAndRemoveEntry((Map.Entry)o);
}
public int size() {
return ConcurrentReaderHashMap.this.size();
}
public void clear() {
ConcurrentReaderHashMap.this.clear();
}
}
/**
* Helper method for entrySet.remove
**/
protected synchronized boolean findAndRemoveEntry(Map.Entry entry) {
Object key = entry.getKey();
Object v = get(key);
if (v != null && v.equals(entry.getValue())) {
remove(key);
return true;
}
else
return false;
}
/**
* Returns an enumeration of the keys in this table.
*
* @return an enumeration of the keys in this table.
* @see Enumeration
* @see #elements()
* @see #keySet()
* @see Map
*/
public Enumeration keys() {
return new KeyIterator();
}
/**
* Returns an enumeration of the values in this table.
* Use the Enumeration methods on the returned object to fetch the elements
* sequentially.
*
* @return an enumeration of the values in this table.
* @see java.util.Enumeration
* @see #keys()
* @see #values()
* @see Map
*/
public Enumeration elements() {
return new ValueIterator();
}
/**
* ConcurrentReaderHashMap collision list entry.
*/
protected static class Entry implements Map.Entry {
/*
The use of volatile for value field ensures that
we can detect status changes without synchronization.
The other fields are never changed, and are
marked as final.
*/
protected final int hash;
protected final Object key;
protected final Entry next;
protected volatile Object value;
Entry(int hash, Object key, Object value, Entry next) {
this.hash = hash;
this.key = key;
this.next = next;
this.value = value;
}
// Map.Entry Ops
public Object getKey() {
return key;
}
/**
* Get the value. Note: In an entrySet or entrySet.iterator,
* unless the set or iterator is used under synchronization of the
* table as a whole (or you can otherwise guarantee lack of
* concurrent modification), <tt>getValue</tt> <em>might</em>
* return null, reflecting the fact that the entry has been
* concurrently removed. However, there are no assurances that
* concurrent removals will be reflected using this method.
*
* @return the current value, or null if the entry has been
* detectably removed.
**/
public Object getValue() {
return value;
}
/**
* Set the value of this entry. Note: In an entrySet or
* entrySet.iterator), unless the set or iterator is used under
* synchronization of the table as a whole (or you can otherwise
* guarantee lack of concurrent modification), <tt>setValue</tt>
* is not strictly guaranteed to actually replace the value field
* obtained via the <tt>get</tt> operation of the underlying hash
* table in multithreaded applications. If iterator-wide
* synchronization is not used, and any other concurrent
* <tt>put</tt> or <tt>remove</tt> operations occur, sometimes
* even to <em>other</em> entries, then this change is not
* guaranteed to be reflected in the hash table. (It might, or it
* might not. There are no assurances either way.)
*
* @param value the new value.
* @return the previous value, or null if entry has been detectably
* removed.
* @exception NullPointerException if the value is <code>null</code>.
*
**/
public Object setValue(Object value) {
if (value == null)
throw new NullPointerException();
Object oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
return (key.equals(e.getKey()) && value.equals(e.getValue()));
}
public int hashCode() {
return key.hashCode() ^ value.hashCode();
}
public String toString() {
return key + "=" + value;
}
}
protected class HashIterator implements Iterator, Enumeration {
protected final Entry[] tab; // snapshot of table
protected int index; // current slot
protected Entry entry = null; // current node of slot
protected Object currentKey; // key for current node
protected Object currentValue; // value for current node
protected Entry lastReturned = null; // last node returned by next
protected HashIterator() {
tab = ConcurrentReaderHashMap.this.getTableForReading();
index = tab.length - 1;
}
public boolean hasMoreElements() { return hasNext(); }
public Object nextElement() { return next(); }
public boolean hasNext() {
/*
currentkey and currentValue are set here to ensure that next()
returns normally if hasNext() returns true. This avoids
surprises especially when final element is removed during
traversal -- instead, we just ignore the removal during
current traversal.
*/
for (;;) {
if (entry != null) {
Object v = entry.value;
if (v != null) {
currentKey = entry.key;
currentValue = v;
return true;
}
else
entry = entry.next;
}
while (entry == null && index >= 0)
entry = tab[index--];
if (entry == null) {
currentKey = currentValue = null;
return false;
}
}
}
protected Object returnValueOfNext() { return entry; }
public Object next() {
if (currentKey == null && !hasNext())
throw new NoSuchElementException();
Object result = returnValueOfNext();
lastReturned = entry;
currentKey = currentValue = null;
entry = entry.next;
return result;
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
ConcurrentReaderHashMap.this.remove(lastReturned.key);
lastReturned = null;
}
}
protected class KeyIterator extends HashIterator {
protected Object returnValueOfNext() { return currentKey; }
}
protected class ValueIterator extends HashIterator {
protected Object returnValueOfNext() { return currentValue; }
}
/**
* Save the state of the <tt>ConcurrentReaderHashMap</tt>
* instance to a stream (i.e.,
* serialize it).
*
* @serialData The <i>capacity</i> of the
* ConcurrentReaderHashMap (the length of the
* bucket array) is emitted (int), followed by the
* <i>size</i> of the ConcurrentReaderHashMap (the number of key-value
* mappings), followed by the key (Object) and value (Object)
* for each key-value mapping represented by the ConcurrentReaderHashMap
* The key-value mappings are emitted in no particular order.
*/
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException {
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
// Write out number of buckets
s.writeInt(table.length);
// Write out size (number of Mappings)
s.writeInt(count);
// Write out keys and values (alternating)
for (int index = table.length-1; index >= 0; index--) {
Entry entry = table[index];
while (entry != null) {
s.writeObject(entry.key);
s.writeObject(entry.value);
entry = entry.next;
}
}
}
/**
* Reconstitute the <tt>ConcurrentReaderHashMap</tt>
* instance from a stream (i.e.,
* deserialize it).
*/
private synchronized void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// Read in the threshold, loadfactor, and any hidden stuff
s.defaultReadObject();
// Read in number of buckets and allocate the bucket array;
int numBuckets = s.readInt();
table = new Entry[numBuckets];
// Read in size (number of Mappings)
int size = s.readInt();
// Read the keys and values, and put the mappings in the table
for (int i=0; i<size; i++) {
Object key = s.readObject();
Object value = s.readObject();
put(key, value);
}
}
/**
* Return the number of slots in this table
**/
public synchronized int capacity() {
return table.length;
}
/**
* Return the load factor
**/
public float loadFactor() {
return loadFactor;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -