一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解Java實現緩存(LRU,FIFO)

詳解Java實現緩存(LRU,FIFO)

2020-09-06 14:39liuyang0 Java教程

本篇文章主要介紹了詳解Java實現緩存(LRU,FIFO) ,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

現在軟件或者網頁的并發量越來越大了,大量請求直接操作數據庫會對數據庫造成很大的壓力,處理大量連接和請求就會需要很長時間,但是實際中百分之80的數據是很少更改的,這樣就可以引入緩存來進行讀取,減少數據庫的壓力。

常用的緩存有redis和memcached,但是有時候一些小場景就可以直接使用java實現緩存,就可以滿足這部分服務的需求。

緩存主要有lru和fifo,lru是least recently used的縮寫,即最近最久未使用,fifo就是先進先出,下面就使用java來實現這兩種緩存。

lru

lru緩存的思想

  • 固定緩存大小,需要給緩存分配一個固定的大小。
  • 每次讀取緩存都會改變緩存的使用時間,將緩存的存在時間重新刷新。
  • 需要在緩存滿了后,將最近最久未使用的緩存刪除,再添加最新的緩存。

按照如上思想,可以使用linkedhashmap來實現lru緩存。

這是linkedhashmap的一個構造函數,傳入的第三個參數accessorder為true的時候,就按訪問順序對linkedhashmap排序,為false的時候就按插入順序,默認是為false的。

當把accessorder設置為true后,就可以將最近訪問的元素置于最前面,這樣就可以滿足上述的第二點。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * constructs an empty <tt>linkedhashmap</tt> instance with the
 * specified initial capacity, load factor and ordering mode.
 *
 * @param initialcapacity the initial capacity
 * @param loadfactor   the load factor
 * @param accessorder   the ordering mode - <tt>true</tt> for
 *     access-order, <tt>false</tt> for insertion-order
 * @throws illegalargumentexception if the initial capacity is negative
 *     or the load factor is nonpositive
 */
public linkedhashmap(int initialcapacity,
           float loadfactor,
           boolean accessorder) {
  super(initialcapacity, loadfactor);
  this.accessorder = accessorder;
}

這是linkedhashmap中另外一個方法,當返回true的時候,就會remove其中最久的元素,可以通過重寫這個方法來控制緩存元素的刪除,當緩存滿了后,就可以通過返回true刪除最久未被使用的元素,達到lru的要求。這樣就可以滿足上述第三點要求。

?
1
2
3
protected boolean removeeldestentry(map.entry<k,v> eldest) {
  return false;
}

由于linkedhashmap是為自動擴容的,當table數組中元素大于capacity * loadfactor的時候,就會自動進行兩倍擴容。但是為了使緩存大小固定,就需要在初始化的時候傳入容量大小和負載因子。

 為了使得到達設置緩存大小不會進行自動擴容,需要將初始化的大小進行計算再傳入,可以將初始化大小設置為(緩存大小 / loadfactor) + 1,這樣就可以在元素數目達到緩存大小時,也不會進行擴容了。這樣就解決了上述第一點問題。

通過上面分析,實現下面的代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.util.linkedhashmap;
import java.util.map;
import java.util.set;
 
public class lru1<k, v> {
  private final int max_cache_size;
  private final float default_load_factory = 0.75f;
 
  linkedhashmap<k, v> map;
 
  public lru1(int cachesize) {
    max_cache_size = cachesize;
    int capacity = (int)math.ceil(max_cache_size / default_load_factory) + 1;
    /*
     * 第三個參數設置為true,代表linkedlist按訪問順序排序,可作為lru緩存
     * 第三個參數設置為false,代表按插入順序排序,可作為fifo緩存
     */
    map = new linkedhashmap<k, v>(capacity, default_load_factory, true) {
      @override
      protected boolean removeeldestentry(map.entry<k, v> eldest) {
        return size() > max_cache_size;
      }
    };
  }
 
  public synchronized void put(k key, v value) {
    map.put(key, value);
  }
 
  public synchronized v get(k key) {
    return map.get(key);
  }
 
  public synchronized void remove(k key) {
    map.remove(key);
  }
 
  public synchronized set<map.entry<k, v>> getall() {
    return map.entryset();
  }
 
  @override
  public string tostring() {
    stringbuilder stringbuilder = new stringbuilder();
    for (map.entry<k, v> entry : map.entryset()) {
      stringbuilder.append(string.format("%s: %s ", entry.getkey(), entry.getvalue()));
    }
    return stringbuilder.tostring();
  }
 
  public static void main(string[] args) {
    lru1<integer, integer> lru1 = new lru1<>(5);
    lru1.put(1, 1);
    lru1.put(2, 2);
    lru1.put(3, 3);
    system.out.println(lru1);
    lru1.get(1);
    system.out.println(lru1);
    lru1.put(4, 4);
    lru1.put(5, 5);
    lru1.put(6, 6);
    system.out.println(lru1);
  }
}

運行結果:

詳解Java實現緩存(LRU,FIFO)

從運行結果中可以看出,實現了lru緩存的思想。

接著使用hashmap和鏈表來實現lru緩存。

主要的思想和上述基本一致,每次添加元素或者讀取元素就將元素放置在鏈表的頭,當緩存滿了之后,就可以將尾結點元素刪除,這樣就實現了lru緩存。

這種方法中是通過自己編寫代碼移動結點和刪除結點,為了防止緩存大小超過限制,每次進行put的時候都會進行檢查,若緩存滿了則刪除尾部元素。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import java.util.hashmap;
 
/**
 * 使用cache和鏈表實現緩存
 */
public class lru2<k, v> {
  private final int max_cache_size;
  private entry<k, v> head;
  private entry<k, v> tail;
 
  private hashmap<k, entry<k, v>> cache;
 
  public lru2(int cachesize) {
    max_cache_size = cachesize;
    cache = new hashmap<>();
  }
 
  public void put(k key, v value) {
    entry<k, v> entry = getentry(key);
    if (entry == null) {
      if (cache.size() >= max_cache_size) {
        cache.remove(tail.key);
        removetail();
      }
    }
    entry = new entry<>();
    entry.key = key;
    entry.value = value;
    movetohead(entry);
    cache.put(key, entry);
  }
 
  public v get(k key) {
    entry<k, v> entry = getentry(key);
    if (entry == null) {
      return null;
    }
    movetohead(entry);
    return entry.value;
  }
 
  public void remove(k key) {
    entry<k, v> entry = getentry(key);
    if (entry != null) {
      if (entry == head) {
        entry<k, v> next = head.next;
        head.next = null;
        head = next;
        head.pre = null;
      } else if (entry == tail) {
        entry<k, v> prev = tail.pre;
        tail.pre = null;
        tail = prev;
        tail.next = null;
      } else {
        entry.pre.next = entry.next;
        entry.next.pre = entry.pre;
      }
      cache.remove(key);
    }
  }
 
  private void removetail() {
    if (tail != null) {
      entry<k, v> prev = tail.pre;
      if (prev == null) {
        head = null;
        tail = null;
      } else {
        tail.pre = null;
        tail = prev;
        tail.next = null;
      }
    }
  }
 
  private void movetohead(entry<k, v> entry) {
    if (entry == head) {
      return;
    }
    if (entry.pre != null) {
      entry.pre.next = entry.next;
    }
    if (entry.next != null) {
      entry.next.pre = entry.pre;
    }
    if (entry == tail) {
      entry<k, v> prev = entry.pre;
      if (prev != null) {
        tail.pre = null;
        tail = prev;
        tail.next = null;
      }
    }
 
    if (head == null || tail == null) {
      head = tail = entry;
      return;
    }
 
    entry.next = head;
    head.pre = entry;
    entry.pre = null;
    head = entry;
  }
 
  private entry<k, v> getentry(k key) {
    return cache.get(key);
  }
 
  private static class entry<k, v> {
    entry<k, v> pre;
    entry<k, v> next;
    k key;
    v value;
  }
 
  @override
  public string tostring() {
    stringbuilder stringbuilder = new stringbuilder();
    entry<k, v> entry = head;
    while (entry != null) {
      stringbuilder.append(string.format("%s:%s ", entry.key, entry.value));
      entry = entry.next;
    }
    return stringbuilder.tostring();
  }
 
  public static void main(string[] args) {
    lru2<integer, integer> lru2 = new lru2<>(5);
    lru2.put(1, 1);
    system.out.println(lru2);
    lru2.put(2, 2);
    system.out.println(lru2);
    lru2.put(3, 3);
    system.out.println(lru2);
    lru2.get(1);
    system.out.println(lru2);
    lru2.put(4, 4);
    lru2.put(5, 5);
    lru2.put(6, 6);
    system.out.println(lru2);
  }
}

運行結果:

詳解Java實現緩存(LRU,FIFO)

fifo

fifo就是先進先出,可以使用linkedhashmap進行實現。

當第三個參數傳入為false或者是默認的時候,就可以實現按插入順序排序,就可以實現fifo緩存了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * constructs an empty <tt>linkedhashmap</tt> instance with the
 * specified initial capacity, load factor and ordering mode.
 *
 * @param initialcapacity the initial capacity
 * @param loadfactor   the load factor
 * @param accessorder   the ordering mode - <tt>true</tt> for
 *     access-order, <tt>false</tt> for insertion-order
 * @throws illegalargumentexception if the initial capacity is negative
 *     or the load factor is nonpositive
 */
public linkedhashmap(int initialcapacity,
           float loadfactor,
           boolean accessorder) {
  super(initialcapacity, loadfactor);
  this.accessorder = accessorder;
}

實現代碼跟上述使用linkedhashmap實現lru的代碼基本一致,主要就是構造函數的傳值有些不同。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.util.linkedhashmap;
import java.util.map;
import java.util.set;
 
public class lru1<k, v> {
  private final int max_cache_size;
  private final float default_load_factory = 0.75f;
 
  linkedhashmap<k, v> map;
 
  public lru1(int cachesize) {
    max_cache_size = cachesize;
    int capacity = (int)math.ceil(max_cache_size / default_load_factory) + 1;
    /*
     * 第三個參數設置為true,代表linkedlist按訪問順序排序,可作為lru緩存
     * 第三個參數設置為false,代表按插入順序排序,可作為fifo緩存
     */
    map = new linkedhashmap<k, v>(capacity, default_load_factory, false) {
      @override
      protected boolean removeeldestentry(map.entry<k, v> eldest) {
        return size() > max_cache_size;
      }
    };
  }
 
  public synchronized void put(k key, v value) {
    map.put(key, value);
  }
 
  public synchronized v get(k key) {
    return map.get(key);
  }
 
  public synchronized void remove(k key) {
    map.remove(key);
  }
 
  public synchronized set<map.entry<k, v>> getall() {
    return map.entryset();
  }
 
  @override
  public string tostring() {
    stringbuilder stringbuilder = new stringbuilder();
    for (map.entry<k, v> entry : map.entryset()) {
      stringbuilder.append(string.format("%s: %s ", entry.getkey(), entry.getvalue()));
    }
    return stringbuilder.tostring();
  }
 
  public static void main(string[] args) {
    lru1<integer, integer> lru1 = new lru1<>(5);
    lru1.put(1, 1);
    lru1.put(2, 2);
    lru1.put(3, 3);
    system.out.println(lru1);
    lru1.get(1);
    system.out.println(lru1);
    lru1.put(4, 4);
    lru1.put(5, 5);
    lru1.put(6, 6);
    system.out.println(lru1);
  }
}

運行結果:

詳解Java實現緩存(LRU,FIFO)

以上就是使用java實現這兩種緩存的方式,從中可以看出,linkedhashmap實現緩存較為容易,因為底層函數對此已經有了支持,自己編寫鏈表實現lru緩存也是借鑒了linkedhashmap中實現的思想。在java中不只是這兩種數據結構可以實現緩存,比如concurrenthashmap、weakhashmap在某些場景下也是可以作為緩存的,到底用哪一種數據結構主要是看場景再進行選擇,但是很多思想都是可以通用的。

原文鏈接:http://www.cnblogs.com/liuyang0/p/6664586.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人区精品一区二区毛片不卡 | 国内精品 大秀视频 日韩精品 | 波多野结衣之高校教师 | 男人扒开女人下身添 | 久久黄色小视频 | 精品福利一区二区免费视频 | 亚洲一区二区三区免费视频 | 国产特黄一级一片免费 | 欧美日韩国产在线人成 | 三上悠亚精品专区久久 | 日本免费一区二区三区 | 午夜国产精品视频在线 | 国产福利在线观看第二区 | 特黄特色大片免费高清视频 | 国产福利不卡视频 | 欧美a级在线观看 | 2018天天弄| 国产99在线观看 | 五月婷婷在线观看 | 免费永久观看美女视频网站网址 | 日本高h | bedfriend泰剧全集免费观看 | 国产灌醉 | 日韩成人一区ftp在线播放 | 日本妻子迷妹网 | 顶级欧美做受xxx000大乳 | 天天操天天干天天做 | 国产精品女同久久免费观看 | 韩国美女豪爽一级毛片 | 久久久精品3d动漫一区二区三区 | 包臀裙女教师波多野结衣 | 免费特黄一区二区三区视频一 | 日韩在线毛片 | 国产99精品成人免费视频 | 99热精品在线免费观看 | 国产精品www夜色影视 | 国产高清在线视频一区二区三区 | 亚洲精品九色在线网站 | 免费观看网站 | 国产理论片在线观看 | 五月天淫 |