物件緩衝池--採用最近最久未使用策略(LRUCache )管理物件,同時帶有事件監聽功能
1.LRUCacheWithListener :邏輯在這裡實現
物件緩衝池---採用最近最久未使用策略管理物件,同時帶有事件監聽功能
工作原理:
採用集合框架(Java.connection包)來實現最近最久未使用物件池
首先構造物件池、設定池的大小
放置物件到池中,儲存時候,池的指標指向該物件,以表明該物件最近最短被使用過
當把新的物件放入到池中時候,池已經滿,那把刪除最久沒有被使用的物件,然後放入物件
當從池中讀取物件時候,根據條件從池中獲得物件;然後把池的指標指向該取出的物件,以表明該物件最近最短被使用過
當池中有物件被清除時候(當成垃圾清除),會觸發相關事件
當池被清空時候,會出發相關事件
這個類參考了org.apache.tomcat.util.collections.LRUCache的實現細節。
當然原始碼採用Hashtable來儲存池的物件列表,這裡採用另外的儲存方式---HashMap來儲存
org.apache.tomcat.util.collections.LRUCache
檔案位置:jakarta-tomcat-5.5.6jakarta-tomcat-connectorsutil
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清掉
相關文章
- 用apache JCS實現物件緩衝Apache物件
- JavaScript WebGL 幀緩衝區物件JavaScriptWeb物件
- 動態更新——緩衝區物件物件
- 監聽某個物件事件的幾種方法物件事件
- 物件有多少個資料塊緩衝在Data buffer中物件
- Unity——物件池管理Unity物件
- 監聽 watch props物件屬性監聽 或深度監聽物件
- MySQL InnoDB緩衝池MySql
- 使用JavaScript給物件修改註冊監聽器JavaScript物件
- javascript擼來擼去(1)-事件監聽與物件屬性JavaScript事件物件
- 同時配置動態監聽與靜態監聽
- 監聽瀏覽器返回,pushState,popstate 事件,window.history物件瀏覽器事件物件
- 最近最久未使用(LRU)頁面置換演算法 C語言實現演算法C語言
- 最近最久未使用(LRU)頁面置換演算法原理及模擬實現演算法
- Debian 12採用 Ubuntu三重緩衝Ubuntu
- 採用四緩衝提高自繪介面的效率
- 帶緩衝的寫並且讀取固定大小byte陣列的物件設計陣列物件
- .NET Core 物件池的使用物件
- wriesharek同時監聽多個埠
- 事件監聽事件
- 《高效學習OpenGL》之緩衝區物件 glGenBuffers(), glBindBuffer(), glBufferData(),glMapBuffer()物件
- vue監聽input是否為空(監聽值為物件某個屬性)Vue物件
- 論如何監聽一個物件的變化物件
- 最近更新過的物件物件
- Flutter事件監聽Flutter事件
- jQuery事件監聽jQuery事件
- 監聽滑鼠事件事件
- JavaScript 事件監聽JavaScript事件
- js 監聽事件JS事件
- 事件和事件監聽器事件
- mysql檢視緩衝池命中率MySql
- 組策略物件物件
- Javascript事件模型系列(三)jQuery中的事件監聽方式及異同點JavaScript事件模型jQuery
- python 物件池Python物件
- 使用 vue 例項更好的監聽事件Vue事件
- jQuery事件物件jQuery事件物件
- JavaScript 事件物件JavaScript事件物件
- 事件物件(轉)事件物件