⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 concurrentreaderhashmap.java

📁 Wicket一个开发Java Web应用程序框架。它使得开发web应用程序变得容易而轻松。 Wicket利用一个POJO data beans组件使得它可以与任何持久层技术相结合。
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*  File: ConcurrentReaderHashMap  Written by Doug Lea. Adapted and released, under explicit  permission, from JDK1.2 HashMap.java and Hashtable.java which  carries the following copyright: * Copyright 1997 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information").  You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun.  History:  Date       Who                What  28oct1999  dl               Created  14dec1999  dl               jmm snapshot  19apr2000  dl               use barrierLock  12jan2001  dl               public release  17nov2001  dl               Minor tunings  20may2002  dl               BarrierLock can now be serialized.  09dec2002  dl               Fix interference checks. */package org.apache.wicket.util.concurrent;import java.io.IOException;import java.io.Serializable;import java.util.AbstractCollection;import java.util.AbstractMap;import java.util.AbstractSet;import java.util.Collection;import java.util.Enumeration;import java.util.Iterator;import java.util.Map;import java.util.NoSuchElementException;import java.util.Set;/** * A version of Hashtable that supports mostly-concurrent reading, but exclusive writing. Because * reads are not limited to periods without writes, a concurrent reader policy is weaker than a * classic reader/writer policy, but is generally faster and allows more concurrency. This class is * a good choice especially for tables that are mainly created by one thread during the start-up * phase of a program, and from then on, are mainly read (with perhaps occasional additions or * removals) in many threads. If you also need concurrency among writes, consider instead using * ConcurrentHashMap. * <p> *  * Successful retrievals using get(key) and containsKey(key) usually run without locking. * Unsuccessful ones (i.e., when the key is not present) do involve brief synchronization (locking). * Also, the size and isEmpty methods are always synchronized. *  * <p> * Because retrieval operations can ordinarily overlap with writing operations (i.e., put, remove, * and their derivatives), retrievals can only be guaranteed to return the results of the most * recently <em>completed</em> operations holding upon their onset. Retrieval operations may or * may not return results reflecting in-progress writing operations. However, the retrieval * operations do always return consistent results -- either those holding before any single * modification or after it, but never a nonsense result. For aggregate operations such as putAll * and clear, concurrent reads may reflect insertion or removal of only some entries. In those rare * contexts in which you use a hash table to synchronize operations across threads (for example, to * prevent reads until after clears), you should either encase operations in synchronized blocks, or * instead use java.util.Hashtable. *  * <p> *  * This class also supports optional guaranteed exclusive reads, simply by surrounding a call within * a synchronized block, as in <br> * <code>ConcurrentReaderHashMap t; ... Object v; <br> * synchronized(t) { v = t.get(k); } </code> <br> *  * But this is not usually necessary in practice. For example, it is generally inefficient to write: *  * <pre> *             ConcurrentReaderHashMap t; ...            // Inefficient version *             Object key; ... *             Object value; ... *             synchronized(t) { *               if (!t.containsKey(key)) *                 t.put(key, value); *                 // other code if not previously present *               } *               else { *                 // other code if it was previously present *               } *             } * </pre> *  * Instead, if the values are intended to be the same in each case, just take advantage of the fact * that put returns null if the key was not previously present: *  * <pre> *             ConcurrentReaderHashMap t; ...                // Use this instead *             Object key; ... *             Object value; ... *             Object oldValue = t.put(key, value); *             if (oldValue == null) { *               // other code if not previously present *             } *             else { *               // other code if it was previously present *             } * </pre> *  * <p> *  * Iterators and Enumerations (i.e., those returned by keySet().iterator(), entrySet().iterator(), * values().iterator(), keys(), and elements()) return elements reflecting the state of the hash * table at some point at or since the creation of the iterator/enumeration. They will return at * most one instance of each element (via next()/nextElement()), but might or might not reflect puts * and removes that have been processed since they were created. They do <em>not</em> throw * ConcurrentModificationException. However, these iterators are designed to be used by only one * thread at a time. Sharing an iterator across multiple threads may lead to unpredictable results * if the table is being concurrently modified. Again, you can ensure interference-free iteration by * enclosing the iteration in a synchronized block. * <p> *  * This class may be used as a direct replacement for any use of java.util.Hashtable that does not * depend on readers being blocked during updates. Like Hashtable but unlike java.util.HashMap, this * class does NOT allow <tt>null</tt> to be used as a key or value. This class is also typically * faster than ConcurrentHashMap when there is usually only one thread updating the table, but * possibly many retrieving values from it. * <p> *  * Implementation note: A slightly faster implementation of this class will be possible once planned * Java Memory Model revisions are in place. *  * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> * Introduction to this package. </a>] *  */public class ConcurrentReaderHashMap extends AbstractMap implements Map, Cloneable, Serializable{	private static final long serialVersionUID = 1L;	/*	 * The basic strategy is an optimistic-style scheme based on the guarantee that the hash table	 * and its lists are always kept in a consistent enough state to be read without locking:	 * 	 * Read operations first proceed without locking, by traversing the apparently correct list of	 * the apparently correct bin. If an entry is found, but not invalidated (value field null), it	 * is returned. If not found, operations must recheck (after a memory barrier) to make sure they	 * are using both the right list and the right table (which can change under resizes). If	 * invalidated, reads must acquire main update lock to wait out the update, and then	 * re-traverse.	 * 	 * All list additions are at the front of each bin, making it easy to check changes, and also	 * fast to traverse. Entry next pointers are never assigned. Remove() builds new nodes when	 * necessary to preserve this.	 * 	 * Remove() (also clear()) invalidates removed nodes to alert read operations that they must	 * wait out the full modifications.	 * 	 */	/** A Serializable class for barrier lock * */	protected static class BarrierLock implements java.io.Serializable	{		private static final long serialVersionUID = 1L;	}	/**	 * Lock used only for its memory effects.	 */	protected final BarrierLock barrierLock = new BarrierLock();	/**	 * field written to only to guarantee lock ordering.	 */	protected transient Object lastWrite;	/**	 * Force a memory synchronization that will cause all readers to see table. Call only when	 * already holding main synch lock.	 * 	 * @param x	 */	protected final void recordModification(Object x)	{		synchronized (barrierLock)		{			lastWrite = x;		}	}	/**	 * Get ref to table; the reference and the cells it accesses will be at least as fresh as from	 * last use of barrierLock	 * 	 * @return table cells	 */	protected final Entry[] getTableForReading()	{		synchronized (barrierLock)		{			return table;		}	}	/**	 * The default initial number of table slots for this table (32). Used when not otherwise	 * specified in constructor.	 */	public static final int DEFAULT_INITIAL_CAPACITY = 32;	/**	 * The minimum capacity, used if a lower value is implicitly specified by either of the	 * constructors with arguments. MUST be a power of two.	 */	private static final int MINIMUM_CAPACITY = 4;	/**	 * The maximum capacity, used if a higher value is implicitly specified by either of the	 * constructors with arguments. MUST be a power of two <= 1<<30.	 */	private static final int MAXIMUM_CAPACITY = 1 << 30;	/**	 * The default load factor for this table (1.0). Used when not otherwise specified in	 * constructor.	 */	public static final float DEFAULT_LOAD_FACTOR = 0.75f;	/**	 * The hash table data.	 */	protected transient Entry[] table;	/**	 * The total number of mappings in the hash table.	 */	protected transient int count;	/**	 * The table is rehashed when its size exceeds this threshold. (The value of this field is	 * always (int)(capacity * loadFactor).)	 * 	 * @serial	 */	protected int threshold;	/**	 * The load factor for the hash table.	 * 	 * @serial	 */	protected float loadFactor;	/**	 * Returns the appropriate capacity (power of two) for the specified initial capacity argument.	 * 	 * @param initialCapacity	 * @return appropriate capacity	 */	private int p2capacity(int initialCapacity)	{		int cap = initialCapacity;		// Compute the appropriate capacity		int result;		if (cap > MAXIMUM_CAPACITY || cap < 0)		{			result = MAXIMUM_CAPACITY;		}		else		{			result = MINIMUM_CAPACITY;			while (result < cap)			{				result <<= 1;			}		}		return result;	}	/**	 * Return hash code for Object x. Since we are using power-of-two tables, it is worth the effort	 * to improve hashcode via the same multiplicative scheme as used in IdentityHashMap.	 * 	 * @param x	 * @return hash code	 */	private static int hash(Object x)	{		int h = x.hashCode();		// Multiply by 127 (quickly, via shifts), and mix in some high		// bits to help guard against bunching of codes that are		// consecutive or equally spaced.		return ((h << 7) - h + (h >>> 9) + (h >>> 17));	}	/**	 * Check for equality of non-null references x and y.	 * 	 * @param x	 * @param y	 * @return equality	 */	protected boolean eq(Object x, Object y)	{		return x == y || x.equals(y);	}	/**	 * Constructs a new, empty map with the specified initial capacity and the specified load	 * factor.	 * 	 * @param initialCapacity	 *            the initial capacity The actual initial capacity is rounded to the nearest power	 *            of two.	 * @param loadFactor	 *            the load factor of the ConcurrentReaderHashMap	 * @throws IllegalArgumentException	 *             if the initial maximum number of elements is less than zero, or if the load	 *             factor is nonpositive.	 */	public ConcurrentReaderHashMap(int initialCapacity, float loadFactor)	{		if (loadFactor <= 0)		{			throw new IllegalArgumentException("Illegal Load factor: " + loadFactor);		}		this.loadFactor = loadFactor;		int cap = p2capacity(initialCapacity);		table = new Entry[cap];		threshold = (int)(cap * loadFactor);	}	/**	 * Constructs a new, empty map with the specified initial capacity and default load factor.	 * 	 * @param initialCapacity	 *            the initial capacity of the ConcurrentReaderHashMap.	 * @throws IllegalArgumentException	 *             if the initial maximum number of elements is less than zero.	 */	public ConcurrentReaderHashMap(int initialCapacity)	{		this(initialCapacity, DEFAULT_LOAD_FACTOR);	}	/**	 * Constructs a new, empty map with a default initial capacity and load factor.	 */	public ConcurrentReaderHashMap()	{		this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);	}	/**	 * Constructs a new map with the same mappings as the given map. The map is created with a	 * capacity of twice the number of mappings in the given map or 16 (whichever is greater), and a	 * default load factor.	 * 	 * @param t	 */	public ConcurrentReaderHashMap(Map t)	{		this(Math.max((int)(t.size() / DEFAULT_LOAD_FACTOR) + 1, 16), DEFAULT_LOAD_FACTOR);		putAll(t);	}	/**	 * Returns the number of key-value mappings in this map.	 * 	 * @return the number of key-value mappings in this map.	 */	public synchronized int size()	{		return count;	}	/**	 * Returns <tt>true</tt> if this map contains no key-value mappings.	 * 	 * @return <tt>true</tt> if this map contains no key-value mappings.	 */	public synchronized boolean isEmpty()	{		return count == 0;	}	/**	 * Returns the value to which the specified key is mapped in this table.	 * 	 * @param key	 *            a key in the table.	 * @return the value to which the key is mapped in this table; <code>null</code> if the key is	 *         not mapped to any value in this table.	 * @exception NullPointerException	 *                if the key is <code>null</code>.	 * @see #put(Object, Object)	 */	public Object get(Object key)	{		// throw null pointer exception if key null		int hash = hash(key);		/*		 * Start off at the apparently correct bin. If entry is found, we need to check after a		 * barrier anyway. If not found, we need a barrier to check if we are actually in right bin.		 * So either way, we encounter only one barrier unless we need to retry. And we only need to		 * fully synchronize if there have been concurrent modifications.		 */		Entry[] tab = table;		int index = hash & (tab.length - 1);		Entry first = tab[index];		Entry e = first;		for (;;)		{			if (e == null)			{				// If key apparently not there, check to				// make sure this was a valid read				Entry[] reread = getTableForReading();				if (tab == reread && first == tab[index])				{					return null;				}				else				{					// Wrong list -- must restart traversal at new first					tab = reread;					e = first = tab[index = hash & (tab.length - 1)];				}			}			else if (e.hash == hash && eq(key, e.key))			{				Object value = e.value;				if (value != null)				{					return value;				}				// Entry was invalidated during deletion. But it could				// have been re-inserted, so we must retraverse.				// To avoid useless contention, get lock to wait out				// modifications				// before retraversing.				synchronized (this)				{					tab = table;				}				e = first = tab[index = hash & (tab.length - 1)];			}			else			{				e = e.next;			}		}	}	/**	 * Tests if the specified object is a key in this table.	 * 	 * @param key	 *            possible key.	 * @return <code>true</code> if and only if the specified object is a key in this table, as	 *         determined by the <tt>equals</tt> method; <code>false</code> otherwise.	 * @exception NullPointerException	 *                if the key is <code>null</code>.	 * @see #contains(Object)	 */	public boolean containsKey(Object key)	{		return get(key) != null;	}	/**	 * Maps the specified <code>key</code> to the specified <code>value</code> in this table.	 * Neither the key nor the value can be <code>null</code>.	 * <p>	 * 	 * The value can be retrieved by calling the <code>get</code> method with a key that is equal	 * to the original key.	 * 	 * @param key	 *            the table key.	 * @param value	 *            the value.	 * @return the previous value of the specified key in this table, or <code>null</code> if it	 *         did not have one.	 * @exception NullPointerException	 *                if the key or value is <code>null</code>.	 * @see Object#equals(Object)	 * @see #get(Object)	 */	public Object put(Object key, Object value)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -