LRU的多种实现方式

一、      关于LRU

LRU 即 Least  Rencetly  Used(最近最少使用)缓存替换策略。在任何LRU算法中,它必定有以下两个策略组成:

1、  退化 策略。根据访问情况,对节点按热度进行排序(hot->cold),以便决定哪些节点是热节点(hot)的,哪些节点是冷节点(cold)的。这个退化的策略,一般按以下两种方式去处理:

l  非集中式。即每命中一次就进行退化操作。

非集中式的退化操作,往往由双向链表的方式去实现。每次命中之后就移动命中节点在链表中的位置。(位置靠前的就是hot的数据)。当然,复杂的策略中,有用queue数组进行hot分级等。

l  集中式。定期去进行退化操作。

在集中式的退化操作,常用的策略是:每次命中之后,记录一个时间戳、定时器时间点等等参数。由一个线程去扫描,定期清除老数据。

2、  清除 策略。即去掉那些cold的数据。

l  替换。这个在操作系统缓存中应该是一个常用的做法。

l  删除。删除掉数据,以腾出空间放新的数据。(因为内存是有限的)

二、      ConcurrentHashMap与LinkedHashMap

在JAVA中,LRU的原生实现是JDK中LinkedHashMap。LinkedHashMap继承自HashMap

【实现原理】 简单说就是HashMap的每个节点做一个双向链表。每次访问这个节点,就把该节点移动到双向链表的头部。满了以后,就从链表的尾部删除。但是LinkedHashMap并是非线程安全(其实现中,双向链表的操作是没有任何线程安全的措施的)。

对于线程安全的HashMap,在JDK中有ConcurrentHashMap原生支持。

【实现原理】采用锁分离机制,把一个HashMap分成多个segement,对每个segement的写操作上锁。同时,他的get()操作是没有锁的,具体思想就是把每个hash槽中的链表的头节点置成final的。对hash槽中链表操作,只能从头部去处理。这样就不会有读不一致的情况出现。这个原理,最好还是看源码,比较清晰。

三、      ConcurrentLRUHashMap的实现方式一:直接包装LinkedHashMap。

即,在LinkedHashMap外层全部加锁。

典型代码:

public V get(Object key) {
 lock.lock();
 try {
 return super.get(key);
 }
 finally {
 lock.unlock();
 }
 }

对LinkedHashMap做包装,所有访问都是带锁委托给LinkedHashMap。这样虽然解决了多线程安全问题。但是,是以严重的性能消耗为代价代价。

四、      ConcurrentLRUHashMap实现方式二:直接改造ConcurrentHashMap

该方案主要是重写ConcurrentHashMap。

1、  给每个Entry加一个timestamp。

2、  每次get命中的话,修改时间戳。

3、  定时统计整个map的总量,如果总量大于某个阈值,则deadline往后推。同时,在put的时候,检查hash槽里面每个节点的时间戳,如果已经过期,就删除掉过期节点。

上述做法,删除操作分布在每次put操作中。所以,删除效率比较高。但是,由于时间片不可控,最终将导致内存爆炸的情况出现。

请看下面一种场景:

横坐标表示一个时间片。面积表示这个时间片里面节点数量。

假定节点命中率为50%(命中后,更新到命中时刻的时间片),每个时间片写入10条新数据。

我们可以在运行过程中,每个时间片定义一个更新一次deadline。在put数据的时候,我们可以检查hash槽中Entry是否过期,如果已经过期,则删掉过期数据。

对于deadline的计算,我们可以设置三个阈值(a<b<c)

a)         totalCount<a     deadline不变

b)         a<totalCount<b   deadline=deadline+cycle

c)         b<totalCount<c   deadline=deadline+2*cycle

d)         totalCount>c     deadline=currentTime

上述看似非常优雅的方案,却隐藏几个严重的问题:

1、  时间片的选择问题。

这个方案中,时间片的选择是一个比较困难的问题。因为,如果系统在一个时间片之内爆掉内存的话,系统将直接崩溃。

当然,这个问题,我们可以加外部限制得方式去控制

2、  deadline 之前的数据,不能很快删除。导致deaddata滞留,浪费大量的内存

假定 deadline之前的数据,约为总数据量的10%。因为删数据操作,只在put的时候。假定每个时间点的put操作,能覆盖20%的hash槽。这个10%*20%=2%,每个时间点,只能删除2%的过期数据。然后,随着时间的推移。这个过程必将趋于稳定。而这个趋于稳定后,内存消耗,至少是capacity的4-5倍。这样的消耗和浪费。是难以承受的。

这个方案,从实际测试来看,情况非常糟糕。所以最终还是放弃了。

五、      ConcurrentLRUHashMap实现方式三:分段实现锁分离+每个段内维护一份退化链表

【实现策略】:

1、锁分离机制。内部分成了多个segement,每个segement是独立加锁,相互不干扰。

2、每个segement内部维护一个双向链表(退化链表)。每次命中/添加,就把节点移动到退化链表头部。

3、每次put操作,通过hash,散到每个segement中,判断segment的容量是否到达阈值。 如果到达阈值,则删除退化链表中最末尾的节点。

【实现】

1、重新定义HashEntry<K,V>

 
 
static class HashEntry<K, V> {
/**
* 键
*/
final K key;
/**
* hash值
*/
final int hash;
/**
* 值
*/
volatile V value;
/**
* hash链指针
*/
final HashEntry<K, V> next;
/**
* 双向链表的下一个节点
*/
HashEntry<K, V> linknext;
/**
* 双向链表的下一个节点
*/
HashEntry<K, V> linkpref;
/**
* 死亡标记
*/
AtomicBoolean dead;
}

2、定义segment

static final class Segment<K, V> extends ReentrantLock implements

			Serializable {

		private static final long serialVersionUID = 1L;

		transient int threshold;

		transient volatile int count;

		transient int modCount;

		transient volatile HashEntry<K, V>[] table;

		transient final HashEntry<K, V> header;// 头节点

}

3、  put操作

代码太长了,见附件吧

4、  get操作

		V get(Object key, int hash) {
			HashEntry<K, V> e = getFirst(hash);
			// 遍历查找
			while (e != null) {
				if (e.hash == hash && key.equals(e.key)) {
					V v = e.value;
					// 把节点移动到头部。
					moveNodeToHeader(e);
					if (v != null)
						return v;
					// 在锁的情况读,必定能读到。
					// tab[index] = new HashEntry<K,V>(key, hash, first, value),
					// value赋值和tab[index]赋值可能会重新排序,重新排序之后,可能会读空值
					// 读到空值的话,在有锁的情况在再读一遍,一定能读!
					return readValueUnderLock(e); // recheck
				}
				e = e.next;
			}
			return null;

六、      ConcurrentLRUHashMap实现方式四:

具体的做法是:

1、  对concurrentHashMap 每个节点加时间戳,每次命中只修改该节点的时间戳。

2、  集中式退化操作,每次命中并不进行退化操作。而是集中式进行退化操作(满的时候,或者时间到了)。

代码:

private static class CountableKey<K,V> implements Comparable<CountableKey<K, V>> {

		public CountableKey(K key,V value) {

			if (value == null) {

				throw new NullPointerException("should not be null");

			}

			this.value = value;

			this.key = key;

			refreshTimeStamp();

		}

		

		public void refreshTimeStamp(){

			timestamp.set(System.currentTimeMillis());

		}

		final V value;

		final K key;

		AtomicLong timestamp = new AtomicLong();

		

		@Override

		public int compareTo(CountableKey<K, V> o) {

			long thisval = this.timestamp.get();

			long anotherVal = o.timestamp.get();

			return (thisval < anotherVal?-1:(thisval == anotherVal?0:1));

		}

	}

该方案的好处:

1、  快速执行get操作。get操作的时间是“concurrentHashMap的get时间+更新时间戳”的时间。

2、  put操作,一般的put操作的时间是“concurrentHashMap的put时间”,只要还未到达容量限制。而到达容量限制以后的,需要进行“退化,清理操作”+put的时间

该方案的 可能存在的问题:

1、  命中率,该算法的命中率同linkedHashMap

2、  清除 策略:

l  满了,执行清楚。缺点:1、会出现某个时刻,写操作卡死(如果正在等待清理的话)

l  定时执行。缺点:1、性能耗费。2、读不一致仍然无法避免。

七、      ConcurrentLRUHashMap实现方式的比较

本文只是抛砖引玉,希望能看到更多好多ConcurrentLRUHashMap的实现方式。由于能力有限。上文提到的第二种实现方式,在实际实现中并不能很好的退化,最终可能导致内存溢出。具体分析如下表

方式 方式一 方式二 方式三 方式四
性能
线程安全 绝对安全 安全 安全 安全
内存消耗 一般 很多 一般 一般
稳定性 稳定 不稳定 稳定 不稳定

总体来说,第三者性较好。

比较方式一和方式三:



源代码如下:

[java]  view plain copy
  1. package com.googlecode.jue.util;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.Serializable;  
  5. import java.util.AbstractCollection;  
  6. import java.util.AbstractMap;  
  7. import java.util.AbstractSet;  
  8. import java.util.Collection;  
  9. import java.util.ConcurrentModificationException;  
  10. import java.util.Enumeration;  
  11. import java.util.Iterator;  
  12. import java.util.Map;  
  13. import java.util.NoSuchElementException;  
  14. import java.util.Set;  
  15. import java.util.concurrent.ConcurrentMap;  
  16. import java.util.concurrent.atomic.AtomicBoolean;  
  17. import java.util.concurrent.locks.ReentrantLock;  
  18.   
  19. /** 
  20.  * 基于ConcurrentHashMap修改的LRUMap 
  21.  *  
  22.  * @author noah 
  23.  *  
  24.  * @param <K> 
  25.  * @param <V> 
  26.  */  
  27. public class ConcurrentLRUHashMap<K, V> extends AbstractMap<K, V> implements  
  28.                 ConcurrentMap<K, V>, Serializable {  
  29.   
  30.         /* 
  31.          * The basic strategy is to subdivide the table among Segments, each of 
  32.          * which itself is a concurrently readable hash table. 
  33.          */  
  34.   
  35.         /* ---------------- Constants -------------- */  
  36.   
  37.         /** 
  38.          *  
  39.          */  
  40.         private static final long serialVersionUID = -5031526786765467550L;  
  41.   
  42.         /** 
  43.          * Segement默认最大数 
  44.          */  
  45.         static final int DEFAULT_SEGEMENT_MAX_CAPACITY = 100;  
  46.   
  47.         /** 
  48.          * The default load factor for this table, used when not otherwise specified 
  49.          * in a constructor. 
  50.          */  
  51.         static final float DEFAULT_LOAD_FACTOR = 0.75f;  
  52.   
  53.         /** 
  54.          * The default concurrency level for this table, used when not otherwise 
  55.          * specified in a constructor. 
  56.          */  
  57.         static final int DEFAULT_CONCURRENCY_LEVEL = 16;  
  58.   
  59.         /** 
  60.          * The maximum capacity, used if a higher value is implicitly specified by 
  61.          * either of the constructors with arguments. MUST be a power of two <= 
  62.          * 1<<30 to ensure that entries are indexable using ints. 
  63.          */  
  64.         static final int MAXIMUM_CAPACITY = 1 << 30;  
  65.   
  66.         /** 
  67.          * The maximum number of segments to allow; used to bound constructor 
  68.          * arguments. 
  69.          */  
  70.         static final int MAX_SEGMENTS = 1 << 16// slightly conservative  
  71.   
  72.         /** 
  73.          * Number of unsynchronized retries in size and containsValue methods before 
  74.          * resorting to locking. This is used to avoid unbounded retries if tables 
  75.          * undergo continuous modification which would make it impossible to obtain 
  76.          * an accurate result. 
  77.          */  
  78.         static final int RETRIES_BEFORE_LOCK = 2;  
  79.   
  80.         /* ---------------- Fields -------------- */  
  81.   
  82.         /** 
  83.          * Mask value for indexing into segments. The upper bits of a key's hash 
  84.          * code are used to choose the segment. 
  85.          */  
  86.         final int segmentMask;  
  87.   
  88.         /** 
  89.          * Shift value for indexing within segments. 
  90.          */  
  91.         final int segmentShift;  
  92.   
  93.         /** 
  94.          * The segments, each of which is a specialized hash table 
  95.          */  
  96.         final Segment<K, V>[] segments;  
  97.   
  98.         transient Set<K> keySet;  
  99.         transient Set<Map.Entry<K, V>> entrySet;  
  100.         transient Collection<V> values;  
  101.   
  102.         /* ---------------- Small Utilities -------------- */  
  103.   
  104.         /** 
  105.          * Applies a supplemental hash function to a given hashCode, which defends 
  106.          * against poor quality hash functions. This is critical because 
  107.          * ConcurrentHashMap uses power-of-two length hash tables, that otherwise 
  108.          * encounter collisions for hashCodes that do not differ in lower or upper 
  109.          * bits. 
  110.          */  
  111.         private static int hash(int h) {  
  112.                 // Spread bits to regularize both segment and index locations,  
  113.                 // using variant of single-word Wang/Jenkins hash.  
  114.                 h += (h << 15) ^ 0xffffcd7d;  
  115.                 h ^= (h >>> 10);  
  116.                 h += (h << 3);  
  117.                 h ^= (h >>> 6);  
  118.                 h += (h << 2) + (h << 14);  
  119.                 return h ^ (h >>> 16);  
  120.         }  
  121.   
  122.         /** 
  123.          * Returns the segment that should be used for key with given hash 
  124.          *  
  125.          * @param hash 
  126.          *            the hash code for the key 
  127.          * @return the segment 
  128.          */  
  129.         final Segment<K, V> segmentFor(int hash) {  
  130.                 return segments[(hash >>> segmentShift) & segmentMask];  
  131.         }  
  132.   
  133.         /* ---------------- Inner Classes -------------- */  
  134.   
  135.         /** 
  136.          * 修改原HashEntry, 
  137.          */  
  138.         static final class HashEntry<K, V> {  
  139.                 /** 
  140.                  * 键 
  141.                  */  
  142.                 final K key;  
  143.   
  144.                 /** 
  145.                  * hash值 
  146.                  */  
  147.                 final int hash;  
  148.   
  149.                 /** 
  150.                  * 值 
  151.                  */  
  152.                 volatile V value;  
  153.   
  154.                 /** 
  155.                  * hash链指针 
  156.                  */  
  157.                 final HashEntry<K, V> next;  
  158.   
  159.                 /** 
  160.                  * 双向链表的下一个节点 
  161.                  */  
  162.                 HashEntry<K, V> linkNext;  
  163.   
  164.                 /** 
  165.                  * 双向链表的上一个节点 
  166.                  */  
  167.                 HashEntry<K, V> linkPrev;  
  168.   
  169.                 /** 
  170.                  * 死亡标记 
  171.                  */  
  172.                 AtomicBoolean dead;  
  173.   
  174.                 HashEntry(K key, int hash, HashEntry<K, V> next, V value) {  
  175.                         this.key = key;  
  176.                         this.hash = hash;  
  177.                         this.next = next;  
  178.                         this.value = value;  
  179.                         dead = new AtomicBoolean(false);  
  180.                 }  
  181.   
  182.                 @SuppressWarnings("unchecked")  
  183.                 static final <K, V> HashEntry<K, V>[] newArray(int i) {  
  184.                         return new HashEntry[i];  
  185.                 }  
  186.         }  
  187.   
  188.         /** 
  189.          * 基于原Segment修改,内部实现一个双向列表 
  190.          *  
  191.          * @author noah 
  192.          *  
  193.          * @param <K> 
  194.          * @param <V> 
  195.          */  
  196.         static final class Segment<K, V> extends ReentrantLock implements Serializable {  
  197.                 /* 
  198.                  * Segments maintain a table of entry lists that are ALWAYS kept in a 
  199.                  * consistent state, so can be read without locking. Next fields of 
  200.                  * nodes are immutable (final). All list additions are performed at the 
  201.                  * front of each bin. This makes it easy to check changes, and also fast 
  202.                  * to traverse. When nodes would otherwise be changed, new nodes are 
  203.                  * created to replace them. This works well for hash tables since the 
  204.                  * bin lists tend to be short. (The average length is less than two for 
  205.                  * the default load factor threshold.) 
  206.                  *  
  207.                  * Read operations can thus proceed without locking, but rely on 
  208.                  * selected uses of volatiles to ensure that completed write operations 
  209.                  * performed by other threads are noticed. For most purposes, the 
  210.                  * "count" field, tracking the number of elements, serves as that 
  211.                  * volatile variable ensuring visibility. This is convenient because 
  212.                  * this field needs to be read in many read operations anyway: 
  213.                  *  
  214.                  * - All (unsynchronized) read operations must first read the "count" 
  215.                  * field, and should not look at table entries if it is 0. 
  216.                  *  
  217.                  * - All (synchronized) write operations should write to the "count" 
  218.                  * field after structurally changing any bin. The operations must not 
  219.                  * take any action that could even momentarily cause a concurrent read 
  220.                  * operation to see inconsistent data. This is made easier by the nature 
  221.                  * of the read operations in Map. For example, no operation can reveal 
  222.                  * that the table has grown but the threshold has not yet been updated, 
  223.                  * so there are no atomicity requirements for this with respect to 
  224.                  * reads. 
  225.                  *  
  226.                  * As a guide, all critical volatile reads and writes to the count field 
  227.                  * are marked in code comments. 
  228.                  */  
  229.   
  230.                 private static final long serialVersionUID = 2249069246763182397L;  
  231.   
  232.                 /** 
  233.                  * The number of elements in this segment's region. 
  234.                  */  
  235.                 transient volatile int count;  
  236.   
  237.                 /** 
  238.                  * Number of updates that alter the size of the table. This is used 
  239.                  * during bulk-read methods to make sure they see a consistent snapshot: 
  240.                  * If modCounts change during a traversal of segments computing size or 
  241.                  * checking containsValue, then we might have an inconsistent view of 
  242.                  * state so (usually) must retry. 
  243.                  */  
  244.                 transient int modCount;  
  245.   
  246.                 /** 
  247.                  * The table is rehashed when its size exceeds this threshold. (The 
  248.                  * value of this field is always <tt>(int)(capacity * 
  249.                  * loadFactor)</tt>.) 
  250.                  */  
  251.                 transient int threshold;  
  252.   
  253.                 /** 
  254.                  * The per-segment table. 
  255.                  */  
  256.                 transient volatile HashEntry<K, V>[] table;  
  257.   
  258.                 /** 
  259.                  * The load factor for the hash table. Even though this value is same 
  260.                  * for all segments, it is replicated to avoid needing links to outer 
  261.                  * object. 
  262.                  *  
  263.                  * @serial 
  264.                  */  
  265.                 final float loadFactor;  
  266.   
  267.                 /** 
  268.                  * 头节点 
  269.                  */  
  270.                 transient final HashEntry<K, V> header;  
  271.                   
  272.                 /** 
  273.                  * Segement最大容量 
  274.                  */  
  275.                 final int maxCapacity;  
  276.   
  277.                 Segment(int maxCapacity, float lf, ConcurrentLRUHashMap<K, V> lruMap) {  
  278.                         this.maxCapacity = maxCapacity;  
  279.                         loadFactor = lf;  
  280.                         setTable(HashEntry.<K, V> newArray(maxCapacity));  
  281.                         header = new HashEntry<K, V>(null, -1nullnull);  
  282.                         header.linkNext = header;  
  283.                         header.linkPrev = header;  
  284.                 }  
  285.   
  286.                 @SuppressWarnings("unchecked")  
  287.                 static final <K, V> Segment<K, V>[] newArray(int i) {  
  288.                         return new Segment[i];  
  289.                 }  
  290.   
  291.                 /** 
  292.                  * Sets table to new HashEntry array. Call only while holding lock or in 
  293.                  * constructor. 
  294.                  */  
  295.                 void setTable(HashEntry<K, V>[] newTable) {  
  296.                         threshold = (int) (newTable.length * loadFactor);  
  297.                         table = newTable;  
  298.                 }  
  299.   
  300.                 /** 
  301.                  * Returns properly casted first entry of bin for given hash. 
  302.                  */  
  303.                 HashEntry<K, V> getFirst(int hash) {  
  304.                         HashEntry<K, V>[] tab = table;  
  305.                         return tab[hash & (tab.length - 1)];  
  306.                 }  
  307.   
  308.                 /** 
  309.                  * Reads value field of an entry under lock. Called if value field ever 
  310.                  * appears to be null. This is possible only if a compiler happens to 
  311.                  * reorder a HashEntry initialization with its table assignment, which 
  312.                  * is legal under memory model but is not known to ever occur. 
  313.                  */  
  314.                 V readValueUnderLock(HashEntry<K, V> e) {  
  315.                         lock();  
  316.                         try {  
  317.                                 return e.value;  
  318.                         } finally {  
  319.                                 unlock();  
  320.                         }  
  321.                 }  
  322.   
  323.                 /* Specialized implementations of map methods */  
  324.   
  325.                 V get(Object key, int hash) {  
  326.                         lock();  
  327.                         try {  
  328.                                 if (count != 0) { // read-volatile  
  329.                                         HashEntry<K, V> e = getFirst(hash);  
  330.                                         while (e != null) {  
  331.                                                 if (e.hash == hash && key.equals(e.key)) {  
  332.                                                         V v = e.value;  
  333.                                                         // 将节点移动到头节点之前  
  334.                                                         moveNodeToHeader(e);  
  335.                                                         if (v != null)  
  336.                                                                 return v;  
  337.                                                         return readValueUnderLock(e); // recheck  
  338.                                                 }  
  339.                                                 e = e.next;  
  340.                                         }  
  341.                                 }  
  342.                                 return null;  
  343.                         } finally {  
  344.                                 unlock();  
  345.                         }  
  346.                 }  
  347.   
  348.                 /** 
  349.                  * 将节点移动到头节点之前 
  350.                  *  
  351.                  * @param entry 
  352.                  */  
  353.                 void moveNodeToHeader(HashEntry<K, V> entry) {  
  354.                         // 先移除,然后插入到头节点的前面  
  355.                         removeNode(entry);  
  356.                         addBefore(entry, header);  
  357.                 }  
  358.   
  359.                 /** 
  360.                  * 将第一个参数代表的节点插入到第二个参数代表的节点之前 
  361.                  *  
  362.                  * @param newEntry 
  363.                  *            需要插入的节点 
  364.                  * @param entry 
  365.                  *            被插入的节点 
  366.                  */  
  367.                 void addBefore(HashEntry<K, V> newEntry, HashEntry<K, V> entry) {  
  368.                         newEntry.linkNext = entry;  
  369.                         newEntry.linkPrev = entry.linkPrev;  
  370.                         entry.linkPrev.linkNext = newEntry;  
  371.                         entry.linkPrev = newEntry;  
  372.                 }  
  373.   
  374.                 /** 
  375.                  * 从双向链中删除该Entry 
  376.                  *  
  377.                  * @param entry 
  378.                  */  
  379.                 void removeNode(HashEntry<K, V> entry) {  
  380.                         entry.linkPrev.linkNext = entry.linkNext;  
  381.                         entry.linkNext.linkPrev = entry.linkPrev;  
  382.                 }  
  383.   
  384.                 boolean containsKey(Object key, int hash) {  
  385.                         lock();  
  386.                         try {  
  387.                                 if (count != 0) { // read-volatile  
  388.                                         HashEntry<K, V> e = getFirst(hash);  
  389.                                         while (e != null) {  
  390.                                                 if (e.hash == hash && key.equals(e.key)) {  
  391.                                                         moveNodeToHeader(e);  
  392.                                                         return true;  
  393.                                                 }  
  394.   
  395.                                                 e = e.next;  
  396.                                         }  
  397.                                 }  
  398.                                 return false;  
  399.                         } finally {  
  400.                                 unlock();  
  401.                         }  
  402.                 }  
  403.   
  404.                 boolean containsValue(Object value) {  
  405.                         lock();  
  406.                         try {  
  407.                                 if (count != 0) { // read-volatile  
  408.                                         HashEntry<K, V>[] tab = table;  
  409.                                         int len = tab.length;  
  410.                                         for (int i = 0; i < len; i++) {  
  411.                                                 for (HashEntry<K, V> e = tab[i]; e != null; e = e.next) {  
  412.                                                         V v = e.value;  
  413.                                                         if (v == null// recheck  
  414.                                                                 v = readValueUnderLock(e);  
  415.                                                         if (value.equals(v)) {  
  416.                                                                 moveNodeToHeader(e);  
  417.                                                                 return true;  
  418.                                                         }  
  419.   
  420.                                                 }  
  421.                                         }  
  422.                                 }  
  423.                                 return false;  
  424.                         } finally {  
  425.                                 unlock();  
  426.                         }  
  427.                 }  
  428.   
  429.                 boolean replace(K key, int hash, V oldValue, V newValue) {  
  430.                         lock();  
  431.                         try {  
  432.                                 HashEntry<K, V> e = getFirst(hash);  
  433.                                 while (e != null && (e.hash != hash || !key.equals(e.key)))  
  434.                                         e = e.next;  
  435.   
  436.                                 boolean replaced = false;  
  437.                                 if (e != null && oldValue.equals(e.value)) {  
  438.                                         replaced = true;  
  439.                                         e.value = newValue;  
  440.                                         // 移动到头部  
  441.                                         moveNodeToHeader(e);  
  442.                                 }  
  443.                                 return replaced;  
  444.                         } finally {  
  445.                                 unlock();  
  446.                         }  
  447.                 }  
  448.   
  449.                 V replace(K key, int hash, V newValue) {  
  450.                         lock();  
  451.                         try {  
  452.                                 HashEntry<K, V> e = getFirst(hash);  
  453.                                 while (e != null && (e.hash != hash || !key.equals(e.key)))  
  454.                                         e = e.next;  
  455.   
  456.                                 V oldValue = null;  
  457.                                 if (e != null) {  
  458.                                         oldValue = e.value;  
  459.                                         e.value = newValue;  
  460.                                         // 移动到头部  
  461.                                         moveNodeToHeader(e);  
  462.                                 }  
  463.                                 return oldValue;  
  464.                         } finally {  
  465.                                 unlock();  
  466.                         }  
  467.                 }  
  468.   
  469.                 V put(K key, int hash, V value, boolean onlyIfAbsent) {  
  470.                         lock();  
  471.                         try {  
  472.                                 int c = count;  
  473.                                 if (c++ > threshold) // ensure capacity  
  474.                                         rehash();  
  475.                                 HashEntry<K, V>[] tab = table;  
  476.                                 int index = hash & (tab.length - 1);  
  477.                                 HashEntry<K, V> first = tab[index];  
  478.                                 HashEntry<K, V> e = first;  
  479.                                 while (e != null && (e.hash != hash || !key.equals(e.key)))  
  480.                                         e = e.next;  
  481.   
  482.                                 V oldValue = null;  
  483.                                 if (e != null) {  
  484.                                         oldValue = e.value;  
  485.                                         if (!onlyIfAbsent) {  
  486.                                                 e.value = value;  
  487.                                                 // 移动到头部  
  488.                                                 moveNodeToHeader(e);  
  489.                                         }  
  490.                                 } else {  
  491.                                         oldValue = null;  
  492.                                         ++modCount;  
  493.                                         HashEntry<K, V> newEntry = new HashEntry<K, V>(key, hash, first, value);  
  494.                                         tab[index] = newEntry;  
  495.                                         count = c; // write-volatile  
  496.                                         // 添加到双向链  
  497.                                         addBefore(newEntry, header);  
  498.                                         // 判断是否达到最大值  
  499.                                         removeEldestEntry();  
  500.                                 }  
  501.                                 return oldValue;  
  502.                         } finally {  
  503.                                 unlock();  
  504.                         }  
  505.                 }  
  506.   
  507.                 void rehash() {  
  508.                         HashEntry<K, V>[] oldTable = table;  
  509.                         int oldCapacity = oldTable.length;  
  510.                         if (oldCapacity >= MAXIMUM_CAPACITY)  
  511.                                 return;  
  512.   
  513.                         /* 
  514.                          * Reclassify nodes in each list to new Map. Because we are using 
  515.                          * power-of-two expansion, the elements from each bin must either 
  516.                          * stay at same index, or move with a power of two offset. We 
  517.                          * eliminate unnecessary node creation by catching cases where old 
  518.                          * nodes can be reused because their next fields won't change. 
  519.                          * Statistically, at the default threshold, only about one-sixth of 
  520.                          * them need cloning when a table doubles. The nodes they replace 
  521.                          * will be garbage collectable as soon as they are no longer 
  522.                          * referenced by any reader thread that may be in the midst of 
  523.                          * traversing table right now. 
  524.                          */  
  525.   
  526.                         HashEntry<K, V>[] newTable = HashEntry.newArray(oldCapacity << 1);  
  527.                         threshold = (int) (newTable.length * loadFactor);  
  528.                         int sizeMask = newTable.length - 1;  
  529.                         for (int i = 0; i < oldCapacity; i++) {  
  530.                                 // We need to guarantee that any existing reads of old Map can  
  531.                                 // proceed. So we cannot yet null out each bin.  
  532.                                 HashEntry<K, V> e = oldTable[i];  
  533.   
  534.                                 if (e != null) {  
  535.                                         HashEntry<K, V> next = e.next;  
  536.                                         int idx = e.hash & sizeMask;  
  537.   
  538.                                         // Single node on list  
  539.                                         if (next == null)  
  540.                                                 newTable[idx] = e;  
  541.   
  542.                                         else {  
  543.                                                 // Reuse trailing consecutive sequence at same slot  
  544.                                                 HashEntry<K, V> lastRun = e;  
  545.                                                 int lastIdx = idx;  
  546.                                                 for (HashEntry<K, V> last = next; last != null; last = last.next) {  
  547.                                                         int k = last.hash & sizeMask;  
  548.                                                         if (k != lastIdx) {  
  549.                                                                 lastIdx = k;  
  550.                                                                 lastRun = last;  
  551.                                                         }  
  552.                                                 }  
  553.                                                 newTable[lastIdx] = lastRun;  
  554.   
  555.                                                 // Clone all remaining nodes  
  556.                                                 for (HashEntry<K, V> p = e; p != lastRun; p = p.next) {  
  557.                                                         int k = p.hash & sizeMask;  
  558.                                                         HashEntry<K, V> n = newTable[k];  
  559.                                                         HashEntry<K, V> newEntry = new HashEntry<K, V>(  
  560.                                                                         p.key, p.hash, n, p.value);  
  561.                                                         // update by Noah  
  562.                                                         newEntry.linkNext = p.linkNext;  
  563.                                                         newEntry.linkPrev = p.linkPrev;  
  564.                                                         newTable[k] = newEntry;  
  565.                                                 }  
  566.                                         }  
  567.                                 }  
  568.                         }  
  569.                         table = newTable;  
  570.                 }  
  571.   
  572.                 /** 
  573.                  * Remove; match on key only if value null, else match both. 
  574.                  */  
  575.                 V remove(Object key, int hash, Object value) {  
  576.                         lock();  
  577.                         try {  
  578.                                 int c = count - 1;  
  579.                                 HashEntry<K, V>[] tab = table;  
  580.                                 int index = hash & (tab.length - 1);  
  581.                                 HashEntry<K, V> first = tab[index];  
  582.                                 HashEntry<K, V> e = first;  
  583.                                 while (e != null && (e.hash != hash || !key.equals(e.key)))  
  584.                                         e = e.next;  
  585.   
  586.                                 V oldValue = null;  
  587.                                 if (e != null) {  
  588.                                         V v = e.value;  
  589.                                         if (value == null || value.equals(v)) {  
  590.                                                 oldValue = v;  
  591.                                                 // All entries following removed node can stay  
  592.                                                 // in list, but all preceding ones need to be  
  593.                                                 // cloned.  
  594.                                                 ++modCount;  
  595.                                                 HashEntry<K, V> newFirst = e.next;  
  596.                                                 for (HashEntry<K, V> p = first; p != e; p = p.next) {  
  597.                                                         newFirst = new HashEntry<K, V>(p.key, p.hash,  
  598.                                                                         newFirst, p.value);  
  599.                                                         newFirst.linkNext = p.linkNext;  
  600.                                                         newFirst.linkPrev = p.linkPrev;  
  601.                                                 }  
  602.                                                 tab[index] = newFirst;  
  603.                                                 count = c; // write-volatile  
  604.                                                 // 移除节点  
  605.                                                 removeNode(e);  
  606.                                         }  
  607.                                 }  
  608.                                 return oldValue;  
  609.                         } finally {  
  610.                                 unlock();  
  611.                         }  
  612.                 }  
  613.   
  614.                 /** 
  615.                  * 移除最旧元素 
  616.                  */  
  617.                 void removeEldestEntry() {  
  618.                         if (count > this.maxCapacity) {  
  619.                                 HashEntry<K, V> eldest = header.linkNext;  
  620.                                 remove(eldest.key, eldest.hash, null);  
  621.                         }  
  622.                 }  
  623.   
  624.                 void clear() {  
  625.                         if (count != 0) {  
  626.                                 lock();  
  627.                                 try {  
  628.                                         HashEntry<K, V>[] tab = table;  
  629.                                         for (int i = 0; i < tab.length; i++)  
  630.                                                 tab[i] = null;  
  631.                                         ++modCount;  
  632.                                         count = 0// write-volatile  
  633.                                 } finally {  
  634.                                         unlock();  
  635.                                 }  
  636.                         }  
  637.                 }  
  638.         }  
  639.   
  640.         /** 
  641.          * 使用指定参数,创建一个ConcurrentLRUHashMap 
  642.          *  
  643.          * @param segementCapacity 
  644.          *            Segement最大容量 
  645.          * @param loadFactor 
  646.          *            加载因子 
  647.          * @param concurrencyLevel 
  648.          *            并发级别 
  649.          */  
  650.         public ConcurrentLRUHashMap(int segementCapacity, float loadFactor,  
  651.                         int concurrencyLevel) {  
  652.                 if (!(loadFactor > 0) || segementCapacity < 0 || concurrencyLevel <= 0)  
  653.                         throw new IllegalArgumentException();  
  654.   
  655.                 if (concurrencyLevel > MAX_SEGMENTS)  
  656.                         concurrencyLevel = MAX_SEGMENTS;  
  657.   
  658.                 // Find power-of-two sizes best matching arguments  
  659.                 int sshift = 0;  
  660.                 int ssize = 1;  
  661.                 while (ssize < concurrencyLevel) {  
  662.                         ++sshift;  
  663.                         ssize <<= 1;  
  664.                 }  
  665.                 segmentShift = 32 - sshift;  
  666.                 segmentMask = ssize - 1;  
  667.                 this.segments = Segment.newArray(ssize);  
  668.   
  669.                 for (int i = 0; i < this.segments.length; ++i)  
  670.                         this.segments[i] = new Segment<K, V>(segementCapacity, loadFactor, this);  
  671.         }  
  672.   
  673.         /** 
  674.          * 使用指定参数,创建一个ConcurrentLRUHashMap 
  675.          *  
  676.          * @param segementCapacity 
  677.          *            Segement最大容量 
  678.          * @param loadFactor 
  679.          *            加载因子 
  680.          */  
  681.         public ConcurrentLRUHashMap(int segementCapacity, float loadFactor) {  
  682.                 this(segementCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);  
  683.         }  
  684.   
  685.         /** 
  686.          * 使用指定参数,创建一个ConcurrentLRUHashMap 
  687.          *  
  688.          * @param segementCapacity 
  689.          *            Segement最大容量 
  690.          */  
  691.         public ConcurrentLRUHashMap(int segementCapacity) {  
  692.                 this(segementCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);  
  693.         }  
  694.   
  695.         /** 
  696.          * 使用默认参数,创建一个ConcurrentLRUHashMap,存放元素最大数默认为1000, 加载因子为0.75,并发级别16 
  697.          */  
  698.         public ConcurrentLRUHashMap() {  
  699.                 this(DEFAULT_SEGEMENT_MAX_CAPACITY, DEFAULT_LOAD_FACTOR,  
  700.                                 DEFAULT_CONCURRENCY_LEVEL);  
  701.         }  
  702.   
  703.         /** 
  704.          * Returns <tt>true</tt> if this map contains no key-value mappings. 
  705.          *  
  706.          * @return <tt>true</tt> if this map contains no key-value mappings 
  707.          */  
  708.         public boolean isEmpty() {  
  709.                 final Segment<K, V>[] segments = this.segments;  
  710.                 /* 
  711.                  * We keep track of per-segment modCounts to avoid ABA problems in which 
  712.                  * an element in one segment was added and in another removed during 
  713.                  * traversal, in which case the table was never actually empty at any 
  714.                  * point. Note the similar use of modCounts in the size() and 
  715.                  * containsValue() methods, which are the only other methods also 
  716.                  * susceptible to ABA problems. 
  717.                  */  
  718.                 int[] mc = new int[segments.length];  
  719.                 int mcsum = 0;  
  720.                 for (int i = 0; i < segments.length; ++i) {  
  721.                         if (segments[i].count != 0)  
  722.                                 return false;  
  723.                         else  
  724.                                 mcsum += mc[i] = segments[i].modCount;  
  725.                 }  
  726.                 // If mcsum happens to be zero, then we know we got a snapshot  
  727.                 // before any modifications at all were made. This is  
  728.                 // probably common enough to bother tracking.  
  729.                 if (mcsum != 0) {  
  730.                         for (int i = 0; i < segments.length; ++i) {  
  731.                                 if (segments[i].count != 0 || mc[i] != segments[i].modCount)  
  732.                                         return false;  
  733.                         }  
  734.                 }  
  735.                 return true;  
  736.         }  
  737.   
  738.         /** 
  739.          * Returns the number of key-value mappings in this map. If the map contains 
  740.          * more than <tt>Integer.MAX_VALUE</tt> elements, returns 
  741.          * <tt>Integer.MAX_VALUE</tt>. 
  742.          *  
  743.          * @return the number of key-value mappings in this map 
  744.          */  
  745.         public int size() {  
  746.                 final Segment<K, V>[] segments = this.segments;  
  747.                 long sum = 0;  
  748.                 long check = 0;  
  749.                 int[] mc = new int[segments.length];  
  750.                 // Try a few times to get accurate count. On failure due to  
  751.                 // continuous async changes in table, resort to locking.  
  752.                 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {  
  753.                         check = 0;  
  754.                         sum = 0;  
  755.                         int mcsum = 0;  
  756.                         for (int i = 0; i < segments.length; ++i) {  
  757.                                 sum += segments[i].count;  
  758.                                 mcsum += mc[i] = segments[i].modCount;  
  759.                         }  
  760.                         if (mcsum != 0) {  
  761.                                 for (int i = 0; i < segments.length; ++i) {  
  762.                                         check += segments[i].count;  
  763.                                         if (mc[i] != segments[i].modCount) {  
  764.                                                 check = -1// force retry  
  765.                                                 break;  
  766.                                         }  
  767.                                 }  
  768.                         }  
  769.                         if (check == sum)  
  770.                                 break;  
  771.                 }  
  772.                 if (check != sum) { // Resort to locking all segments  
  773.                         sum = 0;  
  774.                         for (int i = 0; i < segments.length; ++i)  
  775.                                 segments[i].lock();  
  776.                         for (int i = 0; i < segments.length; ++i)  
  777.                                 sum += segments[i].count;  
  778.                         for (int i = 0; i < segments.length; ++i)  
  779.                                 segments[i].unlock();  
  780.                 }  
  781.                 if (sum > Integer.MAX_VALUE)  
  782.                         return Integer.MAX_VALUE;  
  783.                 else  
  784.                         return (int) sum;  
  785.   
  786.         }  
  787.   
  788.         /** 
  789.          * Returns the value to which the specified key is mapped, or {@code null} 
  790.          * if this map contains no mapping for the key. 
  791.          *  
  792.          * <p> 
  793.          * More formally, if this map contains a mapping from a key {@code k} to a 
  794.          * value {@code v} such that {@code key.equals(k)}, then this method returns 
  795.          * {@code v}; otherwise it returns {@code null}. (There can be at most one 
  796.          * such mapping.) 
  797.          *  
  798.          * @throws NullPointerException 
  799.          *             if the specified key is null 
  800.          */  
  801.         public V get(Object key) {  
  802.                 int hash = hash(key.hashCode());  
  803.                 return segmentFor(hash).get(key, hash);  
  804.         }  
  805.   
  806.         /** 
  807.          * Tests if the specified object is a key in this table. 
  808.          *  
  809.          * @param key 
  810.          *            possible key 
  811.          * @return <tt>true</tt> if and only if the specified object is a key in 
  812.          *         this table, as determined by the <tt>equals</tt> method; 
  813.          *         <tt>false</tt> otherwise. 
  814.          * @throws NullPointerException 
  815.          *             if the specified key is null 
  816.          */  
  817.         public boolean containsKey(Object key) {  
  818.                 int hash = hash(key.hashCode());  
  819.                 return segmentFor(hash).containsKey(key, hash);  
  820.         }  
  821.   
  822.         /** 
  823.          * Returns <tt>true</tt> if this map maps one or more keys to the specified 
  824.          * value. Note: This method requires a full internal traversal of the hash 
  825.          * table, and so is much slower than method <tt>containsKey</tt>. 
  826.          *  
  827.          * @param value 
  828.          *            value whose presence in this map is to be tested 
  829.          * @return <tt>true</tt> if this map maps one or more keys to the specified 
  830.          *         value 
  831.          * @throws NullPointerException 
  832.          *             if the specified value is null 
  833.          */  
  834.         public boolean containsValue(Object value) {  
  835.                 if (value == null)  
  836.                         throw new NullPointerException();  
  837.   
  838.                 // See explanation of modCount use above  
  839.   
  840.                 final Segment<K, V>[] segments = this.segments;  
  841.                 int[] mc = new int[segments.length];  
  842.   
  843.                 // Try a few times without locking  
  844.                 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {  
  845.                         int mcsum = 0;  
  846.                         for (int i = 0; i < segments.length; ++i) {  
  847.                                 mcsum += mc[i] = segments[i].modCount;  
  848.                                 if (segments[i].containsValue(value))  
  849.                                         return true;  
  850.                         }  
  851.                         boolean cleanSweep = true;  
  852.                         if (mcsum != 0) {  
  853.                                 for (int i = 0; i < segments.length; ++i) {  
  854.                                         if (mc[i] != segments[i].modCount) {  
  855.                                                 cleanSweep = false;  
  856.                                                 break;  
  857.                                         }  
  858.                                 }  
  859.                         }  
  860.                         if (cleanSweep)  
  861.                                 return false;  
  862.                 }  
  863.                 // Resort to locking all segments  
  864.                 for (int i = 0; i < segments.length; ++i)  
  865.                         segments[i].lock();  
  866.                 boolean found = false;  
  867.                 try {  
  868.                         for (int i = 0; i < segments.length; ++i) {  
  869.                                 if (segments[i].containsValue(value)) {  
  870.                                         found = true;  
  871.                                         break;  
  872.                                 }  
  873.                         }  
  874.                 } finally {  
  875.                         for (int i = 0; i < segments.length; ++i)  
  876.                                 segments[i].unlock();  
  877.                 }  
  878.                 return found;  
  879.         }  
  880.   
  881.         /** 
  882.          * Legacy method testing if some key maps into the specified value in this 
  883.          * table. This method is identical in functionality to 
  884.          * {@link #containsValue}, and exists solely to ensure full compatibility 
  885.          * with class {@link java.util.Hashtable}, which supported this method prior 
  886.          * to introduction of the Java Collections framework. 
  887.          *  
  888.          * @param value 
  889.          *            a value to search for 
  890.          * @return <tt>true</tt> if and only if some key maps to the <tt>value</tt> 
  891.          *         argument in this table as determined by the <tt>equals</tt> 
  892.          *         method; <tt>false</tt> otherwise 
  893.          * @throws NullPointerException 
  894.          *             if the specified value is null 
  895.          */  
  896.         public boolean contains(Object value) {  
  897.                 return containsValue(value);  
  898.         }  
  899.   
  900.         /** 
  901.          * Put一个键值,加Map锁 
  902.          */  
  903.         public V put(K key, V value) {  
  904.                 if (value == null)  
  905.                         throw new NullPointerException();  
  906.                 int hash = hash(key.hashCode());  
  907.                 return segmentFor(hash).put(key, hash, value, false);  
  908.         }  
  909.   
  910.         /** 
  911.          * Put一个键值,如果该Key不存在的话 
  912.          */  
  913.         public V putIfAbsent(K key, V value) {  
  914.                 if (value == null)  
  915.                         throw new NullPointerException();  
  916.                 int hash = hash(key.hashCode());  
  917.                 return segmentFor(hash).put(key, hash, value, true);  
  918.         }  
  919.   
  920.         /** 
  921.          * Copies all of the mappings from the specified map to this one. These 
  922.          * mappings replace any mappings that this map had for any of the keys 
  923.          * currently in the specified map. 
  924.          *  
  925.          * @param m 
  926.          *            mappings to be stored in this map 
  927.          */  
  928.         public void putAll(Map<? extends K, ? extends V> m) {  
  929.                 for (Map.Entry<? extends K, ? extends V> e : m.entrySet())  
  930.                         put(e.getKey(), e.getValue());  
  931.         }  
  932.   
  933.         /** 
  934.          * Removes the key (and its corresponding value) from this map. This method 
  935.          * does nothing if the key is not in the map. 
  936.          *  
  937.          * @param key 
  938.          *            the key that needs to be removed 
  939.          * @return the previous value associated with <tt>key</tt>, or <tt>null</tt> 
  940.          *         if there was no mapping for <tt>key</tt> 
  941.          * @throws NullPointerException 
  942.          *             if the specified key is null 
  943.          */  
  944.         public V remove(Object key) {  
  945.                 int hash = hash(key.hashCode());  
  946.                 return segmentFor(hash).remove(key, hash, null);  
  947.         }  
  948.   
  949.         /** 
  950.          * {@inheritDoc} 
  951.          *  
  952.          * @throws NullPointerException 
  953.          *             if the specified key is null 
  954.          */  
  955.         public boolean remove(Object key, Object value) {  
  956.                 int hash = hash(key.hashCode());  
  957.                 if (value == null)  
  958.                         return false;  
  959.                 return segmentFor(hash).remove(key, hash, value) != null;  
  960.         }  
  961.   
  962.         /** 
  963.          * {@inheritDoc} 
  964.          *  
  965.          * @throws NullPointerException 
  966.          *             if any of the arguments are null 
  967.          */  
  968.         public boolean replace(K key, V oldValue, V newValue) {  
  969.                 if (oldValue == null || newValue == null)  
  970.                         throw new NullPointerException();  
  971.                 int hash = hash(key.hashCode());  
  972.                 return segmentFor(hash).replace(key, hash, oldValue, newValue);  
  973.         }  
  974.   
  975.         /** 
  976.          * {@inheritDoc} 
  977.          *  
  978.          * @return the previous value associated with the specified key, or 
  979.          *         <tt>null</tt> if there was no mapping for the key 
  980.          * @throws NullPointerException 
  981.          *             if the specified key or value is null 
  982.          */  
  983.         public V replace(K key, V value) {  
  984.                 if (value == null)  
  985.                         throw new NullPointerException();  
  986.                 int hash = hash(key.hashCode());  
  987.                 return segmentFor(hash).replace(key, hash, value);  
  988.         }  
  989.   
  990.         /** 
  991.          * Removes all of the mappings from this map. 
  992.          */  
  993.         public void clear() {  
  994.                 for (int i = 0; i < segments.length; ++i)  
  995.                         segments[i].clear();  
  996.         }  
  997.   
  998.         /** 
  999.          * Returns a {@link Set} view of the keys contained in this map. The set is 
  1000.          * backed by the map, so changes to the map are reflected in the set, and 
  1001.          * vice-versa. The set supports element removal, which removes the 
  1002.          * corresponding mapping from this map, via the <tt>Iterator.remove</tt>, 
  1003.          * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and 
  1004.          * <tt>clear</tt> operations. It does not support the <tt>add</tt> or 
  1005.          * <tt>addAll</tt> operations. 
  1006.          *  
  1007.          * <p> 
  1008.          * The view's <tt>iterator</tt> is a "weakly consistent" iterator that will 
  1009.          * never throw {@link ConcurrentModificationException}, and guarantees to 
  1010.          * traverse elements as they existed upon construction of the iterator, and 
  1011.          * may (but is not guaranteed to) reflect any modifications subsequent to 
  1012.          * construction. 
  1013.          */  
  1014.         public Set<K> keySet() {  
  1015.                 Set<K> ks = keySet;  
  1016.                 return (ks != null) ? ks : (keySet = new KeySet());  
  1017.         }  
  1018.   
  1019.         /** 
  1020.          * Returns a {@link Collection} view of the values contained in this map. 
  1021.          * The collection is backed by the map, so changes to the map are reflected 
  1022.          * in the collection, and vice-versa. The collection supports element 
  1023.          * removal, which removes the corresponding mapping from this map, via the 
  1024.          * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>, <tt>removeAll</tt>, 
  1025.          * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not support 
  1026.          * the <tt>add</tt> or <tt>addAll</tt> operations. 
  1027.          *  
  1028.          * <p> 
  1029.          * The view's <tt>iterator</tt> is a "weakly consistent" iterator that will 
  1030.          * never throw {@link ConcurrentModificationException}, and guarantees to 
  1031.          * traverse elements as they existed upon construction of the iterator, and 
  1032.          * may (but is not guaranteed to) reflect any modifications subsequent to 
  1033.          * construction. 
  1034.          */  
  1035.         public Collection<V> values() {  
  1036.                 Collection<V> vs = values;  
  1037.                 return (vs != null) ? vs : (values = new Values());  
  1038.         }  
  1039.   
  1040.         /** 
  1041.          * Returns a {@link Set} view of the mappings contained in this map. The set 
  1042.          * is backed by the map, so changes to the map are reflected in the set, and 
  1043.          * vice-versa. The set supports element removal, which removes the 
  1044.          * corresponding mapping from the map, via the <tt>Iterator.remove</tt>, 
  1045.          * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and 
  1046.          * <tt>clear</tt> operations. It does not support the <tt>add</tt> or 
  1047.          * <tt>addAll</tt> operations. 
  1048.          *  
  1049.          * <p> 
  1050.          * The view's <tt>iterator</tt> is a "weakly consistent" iterator that will 
  1051.          * never throw {@link ConcurrentModificationException}, and guarantees to 
  1052.          * traverse elements as they existed upon construction of the iterator, and 
  1053.          * may (but is not guaranteed to) reflect any modifications subsequent to 
  1054.          * construction. 
  1055.          */  
  1056.         public Set<Map.Entry<K, V>> entrySet() {  
  1057.                 Set<Map.Entry<K, V>> es = entrySet;  
  1058.                 return (es != null) ? es : (entrySet = new EntrySet());  
  1059.         }  
  1060.   
  1061.         /** 
  1062.          * Returns an enumeration of the keys in this table. 
  1063.          *  
  1064.          * @return an enumeration of the keys in this table 
  1065.          * @see #keySet() 
  1066.          */  
  1067.         public Enumeration<K> keys() {  
  1068.                 return new KeyIterator();  
  1069.         }  
  1070.   
  1071.         /** 
  1072.          * Returns an enumeration of the values in this table. 
  1073.          *  
  1074.          * @return an enumeration of the values in this table 
  1075.          * @see #values() 
  1076.          */  
  1077.         public Enumeration<V> elements() {  
  1078.                 return new ValueIterator();  
  1079.         }  
  1080.   
  1081.         /* ---------------- Iterator Support -------------- */  
  1082.   
  1083.         abstract class HashIterator {  
  1084.                 int nextSegmentIndex;  
  1085.                 int nextTableIndex;  
  1086.                 HashEntry<K, V>[] currentTable;  
  1087.                 HashEntry<K, V> nextEntry;  
  1088.                 HashEntry<K, V> lastReturned;  
  1089.   
  1090.                 HashIterator() {  
  1091.                         nextSegmentIndex = segments.length - 1;  
  1092.                         nextTableIndex = -1;  
  1093.                         advance();  
  1094.                 }  
  1095.   
  1096.                 public boolean hasMoreElements() {  
  1097.                         return hasNext();  
  1098.                 }  
  1099.   
  1100.                 final void advance() {  
  1101.                         if (nextEntry != null && (nextEntry = nextEntry.next) != null)  
  1102.                                 return;  
  1103.   
  1104.                         while (nextTableIndex >= 0) {  
  1105.                                 if ((nextEntry = currentTable[nextTableIndex--]) != null)  
  1106.                                         return;  
  1107.                         }  
  1108.   
  1109.                         while (nextSegmentIndex >= 0) {  
  1110.                                 Segment<K, V> seg = segments[nextSegmentIndex--];  
  1111.                                 if (seg.count != 0) {  
  1112.                                         currentTable = seg.table;  
  1113.                                         for (int j = currentTable.length - 1; j >= 0; --j) {  
  1114.                                                 if ((nextEntry = currentTable[j]) != null) {  
  1115.                                                         nextTableIndex = j - 1;  
  1116.                                                         return;  
  1117.                                                 }  
  1118.                                         }  
  1119.                                 }  
  1120.                         }  
  1121.                 }  
  1122.   
  1123.                 public boolean hasNext() {  
  1124.                         return nextEntry != null;  
  1125.                 }  
  1126.   
  1127.                 HashEntry<K, V> nextEntry() {  
  1128.                         if (nextEntry == null)  
  1129.                                 throw new NoSuchElementException();  
  1130.                         lastReturned = nextEntry;  
  1131.                         advance();  
  1132.                         return lastReturned;  
  1133.                 }  
  1134.   
  1135.                 public void remove() {  
  1136.                         if (lastReturned == null)  
  1137.                                 throw new IllegalStateException();  
  1138.                         ConcurrentLRUHashMap.this.remove(lastReturned.key);  
  1139.                         lastReturned = null;  
  1140.                 }  
  1141.         }  
  1142.   
  1143.         final class KeyIterator extends HashIterator implements Iterator<K>,  
  1144.                         Enumeration<K> {  
  1145.                 public K next() {  
  1146.                         return super.nextEntry().key;  
  1147.                 }  
  1148.   
  1149.                 public K nextElement() {  
  1150.                         return super.nextEntry().key;  
  1151.                 }  
  1152.         }  
  1153.   
  1154.         final class ValueIterator extends HashIterator implements Iterator<V>,  
  1155.                         Enumeration<V> {  
  1156.                 public V next() {  
  1157.                         return super.nextEntry().value;  
  1158.                 }  
  1159.   
  1160.                 public V nextElement() {  
  1161.                         return super.nextEntry().value;  
  1162.                 }  
  1163.         }  
  1164.   
  1165.         /** 
  1166.          * Custom Entry class used by EntryIterator.next(), that relays setValue 
  1167.          * changes to the underlying map. 
  1168.          */  
  1169.         final class WriteThroughEntry extends AbstractMap.SimpleEntry<K, V> {  
  1170.                 /** 
  1171.                  *  
  1172.                  */  
  1173.                 private static final long serialVersionUID = -2545938966452012894L;  
  1174.   
  1175.                 WriteThroughEntry(K k, V v) {  
  1176.                         super(k, v);  
  1177.                 }  
  1178.   
  1179.                 /** 
  1180.                  * Set our entry's value and write through to the map. The value to 
  1181.                  * return is somewhat arbitrary here. Since a WriteThroughEntry does not 
  1182.                  * necessarily track asynchronous changes, the most recent "previous" 
  1183.                  * value could be different from what we return (or could even have been 
  1184.                  * removed in which case the put will re-establish). We do not and 
  1185.                  * cannot guarantee more. 
  1186.                  */  
  1187.                 public V setValue(V value) {  
  1188.                         if (value == null)  
  1189.                                 throw new NullPointerException();  
  1190.                         V v = super.setValue(value);  
  1191.                         ConcurrentLRUHashMap.this.put(getKey(), value);  
  1192.                         return v;  
  1193.                 }  
  1194.         }  
  1195.   
  1196.         final class EntryIterator extends HashIterator implements  
  1197.                         Iterator<Entry<K, V>> {  
  1198.                 public Map.Entry<K, V> next() {  
  1199.                         HashEntry<K, V> e = super.nextEntry();  
  1200.                         return new WriteThroughEntry(e.key, e.value);  
  1201.                 }  
  1202.         }  
  1203.   
  1204.         final class KeySet extends AbstractSet<K> {  
  1205.                 public Iterator<K> iterator() {  
  1206.                         return new KeyIterator();  
  1207.                 }  
  1208.   
  1209.                 public int size() {  
  1210.                         return ConcurrentLRUHashMap.this.size();  
  1211.                 }  
  1212.   
  1213.                 public boolean contains(Object o) {  
  1214.                         return ConcurrentLRUHashMap.this.containsKey(o);  
  1215.                 }  
  1216.   
  1217.                 public boolean remove(Object o) {  
  1218.                         return ConcurrentLRUHashMap.this.remove(o) != null;  
  1219.                 }  
  1220.   
  1221.                 public void clear() {  
  1222.                         ConcurrentLRUHashMap.this.clear();  
  1223.                 }  
  1224.         }  
  1225.   
  1226.         final class Values extends AbstractCollection<V> {  
  1227.                 public Iterator<V> iterator() {  
  1228.                         return new ValueIterator();  
  1229.                 }  
  1230.   
  1231.                 public int size() {  
  1232.                         return ConcurrentLRUHashMap.this.size();  
  1233.                 }  
  1234.   
  1235.                 public boolean contains(Object o) {  
  1236.                         return ConcurrentLRUHashMap.this.containsValue(o);  
  1237.                 }  
  1238.   
  1239.                 public void clear() {  
  1240.                         ConcurrentLRUHashMap.this.clear();  
  1241.                 }  
  1242.         }  
  1243.   
  1244.         final class EntrySet extends AbstractSet<Map.Entry<K, V>> {  
  1245.                 public Iterator<Map.Entry<K, V>> iterator() {  
  1246.                         return new EntryIterator();  
  1247.                 }  
  1248.   
  1249.                 public boolean contains(Object o) {  
  1250.                         if (!(o instanceof Map.Entry))  
  1251.                                 return false;  
  1252.                         Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;  
  1253.                         V v = ConcurrentLRUHashMap.this.get(e.getKey());  
  1254.                         return v != null && v.equals(e.getValue());  
  1255.                 }  
  1256.   
  1257.                 public boolean remove(Object o) {  
  1258.                         if (!(o instanceof Map.Entry))  
  1259.                                 return false;  
  1260.                         Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;  
  1261.                         return ConcurrentLRUHashMap.this.remove(e.getKey(), e.getValue());  
  1262.                 }  
  1263.   
  1264.                 public int size() {  
  1265.                         return ConcurrentLRUHashMap.this.size();  
  1266.                 }  
  1267.   
  1268.                 public void clear() {  
  1269.                         ConcurrentLRUHashMap.this.clear();  
  1270.                 }  
  1271.         }  
  1272.   
  1273.         /* ---------------- Serialization Support -------------- */  
  1274.   
  1275.         /** 
  1276.          * Save the state of the <tt>ConcurrentHashMap</tt> instance to a stream 
  1277.          * (i.e., serialize it). 
  1278.          *  
  1279.          * @param s 
  1280.          *            the stream 
  1281.          * @serialData the key (Object) and value (Object) for each key-value 
  1282.          *             mapping, followed by a null pair. The key-value mappings are 
  1283.          *             emitted in no particular order. 
  1284.          */  
  1285.         private void writeObject(java.io.ObjectOutputStream s) throws IOException {  
  1286.                 s.defaultWriteObject();  
  1287.   
  1288.                 for (int k = 0; k < segments.length; ++k) {  
  1289.                         Segment<K, V> seg = segments[k];  
  1290.                         seg.lock();  
  1291.                         try {  
  1292.                                 HashEntry<K, V>[] tab = seg.table;  
  1293.                                 for (int i = 0; i < tab.length; ++i) {  
  1294.                                         for (HashEntry<K, V> e = tab[i]; e != null; e = e.next) {  
  1295.                                                 s.writeObject(e.key);  
  1296.                                                 s.writeObject(e.value);  
  1297.                                         }  
  1298.                                 }  
  1299.                         } finally {  
  1300.                                 seg.unlock();  
  1301.                         }  
  1302.                 }  
  1303.                 s.writeObject(null);  
  1304.                 s.writeObject(null);  
  1305.         }  
  1306.   
  1307.         /** 
  1308.          * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a stream (i.e., 
  1309.          * deserialize it). 
  1310.          *  
  1311.          * @param s 
  1312.          *            the stream 
  1313.          */  
  1314.         @SuppressWarnings("unchecked")  
  1315.         private void readObject(java.io.ObjectInputStream s) throws IOException,  
  1316.                         ClassNotFoundException {  
  1317.                 s.defaultReadObject();  
  1318.   
  1319.                 // Initialize each segment to be minimally sized, and let grow.  
  1320.                 for (int i = 0; i < segments.length; ++i) {  
  1321.                         segments[i].setTable(new HashEntry[1]);  
  1322.                 }  
  1323.   
  1324.                 // Read the keys and values, and put the mappings in the table  
  1325.                 for (;;) {  
  1326.                         K key = (K) s.readObject();  
  1327.                         V value = (V) s.readObject();  
  1328.                         if (key == null)  
  1329.                                 break;  
  1330.                         put(key, value);  
  1331.                 }  
  1332.         }  
  1333. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值