进入高产模式
。这一篇呢,我们来学一哈儿LinkedHashMap,这个LinkedHashMap。在缓存算法中有一个LRU(Least Recently Used的缩写,最近最少使用)算法,我们便可以通过这个LinkedHashMap去完成这个算法,具体实现我们会在后面贴出来。现在我们进入我们探讨的正常流程。在看这一篇之前建议先去了解 HashMap。简介
-
Map接口的哈希表与链表实现,这个跟HashMap不一样的地方有这么一个,就是有可预测的顺序,我们会在下面说到。这个实现不同于HashMap的地方是它内部维护了一个关联所有键值对的双相链表,这个链表定义了迭代的顺序是按照插入时的顺序还是访问时的顺序。
-
LinkedHashMap提供了一个构造函数,能使原有的Map转变为LinkedHashMap,并且这个LinkedHashMap中元素的顺序与源中元素顺序相同。
-
LinkedHashMap提供了一个构造函数LinkedHashMap(int,float,boolean) ,我们能通过这个构造函数指定排序顺序。当为ture时,LinkedHashMap会将按照访问的顺序进行排序。
-
removeEldestEntry这个方法便是LinkedHashMap判断是否删除元素的依据,当为true时,删除第一个元素。如果要使用一般需要重写。
-
这个类提供所有map的可选操作,并且允许null元素。想HashMap一样,对基本操作如add、contains、remove他提供恒定时间的性能表现。并且性能比HashMap只低一点点,因为要维护一个双向链表。对所有元素进行迭代,在LinkedHashMap中这个所需要的时间与其size成正比。但是HashMap花费更多,需要与其容量成正比的时间。
-
有两个参数影响其性能,initial capacity与load factor 他们的定义与在HashMap中的完全相同。
-
这个实现不是同步的,如果有多个线程访问,并且至少有一个线程对其进行了结构修改,必须要进行额外的操作保证其线程安全性,比如使用Map m = Collections.synchronizedMap(new LinkedHashMap(...));
-
这里的结构改变与其他的集合类有些不同,在这个LinkedHashMap是以访问顺序进行排序时,get也算结构改变。
-
这个类返回的所有迭代器Iterator都是基于快速失败机制fail-fast的。
-
这个类返回的分裂迭代器Spliterator是后期绑定以及快速失败的,并且被标记为ORDERED。
存储结构
LinkedHashMap继承于HashMap,所以LinkedHashMap除了双向链表外,其他的都与HashMap大同小异。在这一篇,我们将关注点放到LinkedHashMap的实际使用上,所以存储结构我们用图来解释。
展示的有些乱,但是大题存储结构画出来了,与HashMap相比其实就是多了一个双向链表。实际应用
我们现在利用LinkedHashMap来做一个简单的LRU。
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author lichaobao
* @date 2019/5/30
* @QQ 1527563274
*/
public class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V> {
private int capacity;
public LRULinkedHashMap(int capacity){
super(4,0.75f,true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
boolean ifRemove = size() > capacity;
if(ifRemove){
System.out.println("内存不够即将删除:"+eldest.getKey()+"="+eldest.getValue());
}
return ifRemove;
}
public static void main(String[] args){
Map<Integer,String> map = new LRULinkedHashMap<Integer, String>(4);
map.put(1,"one");
map.put(2,"two");
map.put(3,"three");
map.put(4,"four");
System.out.println("==========访问前数据顺序==============");
map.forEach((key,value)->{
System.out.print(key+"="+value+" ");
});
System.out.println("\n============现在开始get(1)=============");
System.out.println(map.get(1));
System.out.println("==========访问1后数据顺序==============");
map.forEach((key,value)->{
System.out.print(key+"="+value+" ");
});
System.out.println("\n==============现在开始增加第五个数据 put(5,\"five\")==========");
map.put(5,"five");
System.out.println("================最后map中的元素以及顺序为================");
map.forEach((key,value)->{
System.out.print(key+"="+value+" ");
});
}
}
复制代码
最后运行结果如下:
总结
- LinkedHashMap除了多了一个双向链表外与HashMap大致相同,比如扩容、存储机制等。
- 支持两种自动排序,一种是按照插入时的顺序排序,一种是按照访问时的顺序排序,可以通过构造函数LinkedHashMap(int,float,boolean) 来选择。
- 比较适合用来做LRU
- 非同步容器