扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
1.LRUCacheWithListener :逻辑在这里实现
对象缓冲池---采用最近最久未使用策略管理对象,同时带有事件监听功能
工作原理:
采用集合框架(java.connection包)来实现最近最久未使用对象池
首先构造对象池、设置池的大小
放置对象到池中,保存时候,池的指针指向该对象,以表明该对象最近最短被使用过
当把新的对象放入到池中时候,池已经满,那把删除最久没有被使用的对象,然后放入对象
当从池中读取对象时候,根据条件从池中获得对象;然后把池的指针指向该取出的对象,以表明该对象最近最短被使用过
当池中有对象被清除时候(当成垃圾清除),会触发相关事件
当池被清空时候,会出发相关事件
这个类参考了org.apache.tomcat.util.collections.LRUCache的实现细节。
当然原代码采用Hashtable来存储池的对象列表,这里采用另外的存储方式---HashMap来存储
org.apache.tomcat.util.collections.LRUCache
文件位置:jakarta-tomcat-5.5.6\jakarta-tomcat-connectors\util
import java.util.*;
public class LRUCacheWithListener {
/**
* 池对象的包裹类,这样便于相关处理
* **/
class CacheNode {
CacheNode prev;
CacheNode next;
Abandon value;
Object key;
public CacheNode() {
}
}
/**
* 对象池大小
**/
private int cacheSize;
/**
* 对象列表、当然可以采用泛型编程,这样就实现自动装箱、解箱(boxing/unboxing)
* **/
private HashMap nodes;
/**
* 对象池当前对象数
* **/
private int currentSize;
/**
* 第一个节点
* **/
private CacheNode first;
/***
* 最后一个节点
* **/
private CacheNode last;
/**
* 对象锁
* 实际上下面也就几个地方使用了该锁,可以用同步方法来取代调使用这个对象锁
* **/
private static int DEFAULT_SIZE = 10;
public LRUCacheWithListener() {
this(DEFAULT_SIZE);
}
public LRUCacheWithListener(int poolSize) {
cacheSize = poolSize;
currentSize = 0;
first = null; //
last = null; //
nodes = new HashMap(poolSize);
}
/**
* 读取一个对象
* ***/
public synchronized Object get(Object key) {
CacheNode node = (CacheNode) nodes.get(key);
if (node != null) {
moveToHead(node);
return node.value;
} else {
return null;
}
}
/**
* 把指定对象移动到链表的头部
* */
private void moveToHead(CacheNode node) {
if (node == first) {
return;
}
if (node.prev != null) {
node.prev.next = node.next;
}
if (node.next != null) {
node.next.prev = node.prev;
}
if (last == node) {
last = node.prev;
}
if (first != null) {
node.next = first;
first.prev = node;
}
first = node;
node.prev = null;
if (last == null) {
last = first;
}
}
/**
* 删除池中指定对象
* **/
public synchronized Object remove(Object key) {
CacheNode node = (CacheNode) nodes.get(key);
if (node != null) {
if (node.prev != null) {
node.prev.next = node.next;
}
if (node.next != null) {
node.next.prev = node.prev;
}
if (last == node) {
last = node.prev;
}
if (first == node) {
first = node.next;
}
}
return node;
}
/****
* 放置一个对象到池中
* */
public synchronized void put(Object key, Abandon value) {
CacheNode node = (CacheNode) nodes.get(key);
if (node == null) {
//池满,删除最久没有使用的对象
if (currentSize >= cacheSize) {
if (last != null) {
nodes.remove(last.key);
}
removeLast();
}
//池没有满,直接把对象放入池中
else {
currentSize++;
}
node = getANewCacheNode();
}
node.value = value;
node.key = key;
// 把放入池的这个对象移动到链表的头部,表示最近最短被使用过
moveToHead(node);
nodes.put(key, node);
}
/**清空池中对象
* **/
public synchronized void clear() {
// if (first != null) {
// Iterator i = nodes.values().iterator();
// //触发事件,该池已经被清空
// CacheNode n;
// while (i.hasNext()) {
// n = (CacheNode) (i.next());
// n.value.poolClear();
// }
// }
while(!nodes.isEmpty()){
//add by jeff
if (last != null) {
nodes.remove(last.key);
}
removeLast(); //从池中将对象一个个移除
}
first = null;
last = null;
}
/***
* 获得一个新的包裹对象
* **/
private CacheNode getANewCacheNode() {
CacheNode node = new CacheNode();
return node;
}
/**
* 删除池中最久没有使用的对象
* **/
private void removeLast() {
if (last != null) {
//对象从池中被抛弃,触发事件
last.value.onAbandon();
if (last.prev != null) {
last.prev.next = null;
} else {
first = null;
}
last = last.prev;
}
}
}
2.Abandon :定义对象被抛弃和池被清空的事件接口
public interface Abandon {
public void onAbandon();
}
3.CacheNodeWithListener 测试类
public class CacheNodeWithListener implements Abandon {
int id;
public CacheNodeWithListener() {
}
public CacheNodeWithListener(int i) {
id = i;
}
/**
* 当对象被池所抛弃时候,进行相关处理
* ***/
public void onAbandon() {
System.out.println(this +"---onAbandon()");
}
public String toString() {
return "id=" + id;
}
static public void main(String[] s) {
LRUCacheWithListener pool = new LRUCacheWithListener(3); //LRUCacheWithListener(int poolSize) 对象池大小
int i;
for (i = 1; i <= 5; i++) {
pool.put("obj" + i, new CacheNodeWithListener(i));
System.out.println("obj--"+i);
}
System.out.println("obj"+4+":"+pool.get("obj"+4));
pool.clear();//把 《对象池全清空》,poolSize有多大清多少
//检查pool里的对象是否全清掉
for (i = 1; i <= 5; i++) {
System.out.println("obj"+i+":"+pool.get("obj"+i));
}
}
}
4.结论:打印结果
当poolSize为3,而有5个对象需要加入,打印结果如下:
obj--1
obj--2
obj--3
id=1---onAbandon()
obj--4
id=2---onAbandon()
obj--5
obj4:id=4
id=3---onAbandon()
id=5---onAbandon()
id=4---onAbandon()
obj1:null
obj2:null
obj3:null
obj4:null
obj5:null
解析:先放入3个对象,第四个对象加入时抛弃最先加入的对象1
第五个对象加入时抛弃最二先加入的对象2,最后clear就把
内存中的3,4,5清掉
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者