真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java緩存使用如何實(shí)現(xiàn)的

這篇文章將為大家詳細(xì)講解有關(guān)Java緩存使用如何實(shí)現(xiàn)的,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

網(wǎng)站設(shè)計(jì)制作過(guò)程拒絕使用模板建站;使用PHP+MYSQL原生開(kāi)發(fā)可交付網(wǎng)站源代碼;符合網(wǎng)站優(yōu)化排名的后臺(tái)管理系統(tǒng);成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)收費(fèi)合理;免費(fèi)進(jìn)行網(wǎng)站備案等企業(yè)網(wǎng)站建設(shè)一條龍服務(wù).我們是一家持續(xù)穩(wěn)定運(yùn)營(yíng)了十多年的成都創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司。

Java緩存主要有LRU和FIFO,LRU是Least Recently Used的縮寫,即最近最久未使用,F(xiàn)IFO就是先進(jìn)先出,下面就使用Java來(lái)實(shí)現(xiàn)這兩種緩存。

LRU

LRU緩存的思想

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

按照如上思想,可以使用LinkedHashMap來(lái)實(shí)現(xiàn)LRU緩存。

這是LinkedHashMap的一個(gè)構(gòu)造函數(shù),傳入的第三個(gè)參數(shù)accessOrder為true的時(shí)候,就按訪問(wèn)順序?qū)inkedHashMap排序,為false的時(shí)候就按插入順序,默認(rèn)是為false的。

當(dāng)把a(bǔ)ccessOrder設(shè)置為true后,就可以將最近訪問(wèn)的元素置于最前面,這樣就可以滿足上述的第二點(diǎn)。

/**
 * Constructs an empty LinkedHashMap 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 - true for
 *     access-order, false 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中另外一個(gè)方法,當(dāng)返回true的時(shí)候,就會(huì)remove其中最久的元素,可以通過(guò)重寫這個(gè)方法來(lái)控制緩存元素的刪除,當(dāng)緩存滿了后,就可以通過(guò)返回true刪除最久未被使用的元素,達(dá)到LRU的要求。這樣就可以滿足上述第三點(diǎn)要求。

protected boolean removeEldestEntry(Map.Entry eldest) {
  return false;
}

由于LinkedHashMap是為自動(dòng)擴(kuò)容的,當(dāng)table數(shù)組中元素大于Capacity * loadFactor的時(shí)候,就會(huì)自動(dòng)進(jìn)行兩倍擴(kuò)容。但是為了使緩存大小固定,就需要在初始化的時(shí)候傳入容量大小和負(fù)載因子。

 為了使得到達(dá)設(shè)置緩存大小不會(huì)進(jìn)行自動(dòng)擴(kuò)容,需要將初始化的大小進(jìn)行計(jì)算再傳入,可以將初始化大小設(shè)置為(緩存大小 / loadFactor) + 1,這樣就可以在元素?cái)?shù)目達(dá)到緩存大小時(shí),也不會(huì)進(jìn)行擴(kuò)容了。這樣就解決了上述第一點(diǎn)問(wèn)題。

通過(guò)上面分析,實(shí)現(xiàn)下面的代碼

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class LRU1 {
  private final int MAX_CACHE_SIZE;
  private final float DEFAULT_LOAD_FACTORY = 0.75f;

  LinkedHashMap map;

  public LRU1(int cacheSize) {
    MAX_CACHE_SIZE = cacheSize;
    int capacity = (int)Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTORY) + 1;
    /*
     * 第三個(gè)參數(shù)設(shè)置為true,代表linkedlist按訪問(wèn)順序排序,可作為L(zhǎng)RU緩存
     * 第三個(gè)參數(shù)設(shè)置為false,代表按插入順序排序,可作為FIFO緩存
     */
    map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTORY, true) {
      @Override
      protected boolean removeEldestEntry(Map.Entry 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> getAll() {
    return map.entrySet();
  }

  @Override
  public String toString() {
    StringBuilder stringBuilder = new StringBuilder();
    for (Map.Entry entry : map.entrySet()) {
      stringBuilder.append(String.format("%s: %s ", entry.getKey(), entry.getValue()));
    }
    return stringBuilder.toString();
  }

  public static void main(String[] args) {
    LRU1 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);
  }
}

運(yùn)行結(jié)果:

Java緩存使用如何實(shí)現(xiàn)的

從運(yùn)行結(jié)果中可以看出,實(shí)現(xiàn)了LRU緩存的思想。

接著使用HashMap和鏈表來(lái)實(shí)現(xiàn)LRU緩存。

主要的思想和上述基本一致,每次添加元素或者讀取元素就將元素放置在鏈表的頭,當(dāng)緩存滿了之后,就可以將尾結(jié)點(diǎn)元素刪除,這樣就實(shí)現(xiàn)了LRU緩存。

這種方法中是通過(guò)自己編寫代碼移動(dòng)結(jié)點(diǎn)和刪除結(jié)點(diǎn),為了防止緩存大小超過(guò)限制,每次進(jìn)行put的時(shí)候都會(huì)進(jìn)行檢查,若緩存滿了則刪除尾部元素。

import java.util.HashMap;

/**
 * 使用cache和鏈表實(shí)現(xiàn)緩存
 */
public class LRU2 {
  private final int MAX_CACHE_SIZE;
  private Entry head;
  private Entry tail;

  private HashMap> cache;

  public LRU2(int cacheSize) {
    MAX_CACHE_SIZE = cacheSize;
    cache = new HashMap<>();
  }

  public void put(K key, V value) {
    Entry 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 entry = getEntry(key);
    if (entry == null) {
      return null;
    }
    moveToHead(entry);
    return entry.value;
  }

  public void remove(K key) {
    Entry entry = getEntry(key);
    if (entry != null) {
      if (entry == head) {
        Entry next = head.next;
        head.next = null;
        head = next;
        head.pre = null;
      } else if (entry == tail) {
        Entry 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 prev = tail.pre;
      if (prev == null) {
        head = null;
        tail = null;
      } else {
        tail.pre = null;
        tail = prev;
        tail.next = null;
      }
    }
  }

  private void moveToHead(Entry 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 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 getEntry(K key) {
    return cache.get(key);
  }

  private static class Entry {
    Entry pre;
    Entry next;
    K key;
    V value;
  }

  @Override
  public String toString() {
    StringBuilder stringBuilder = new StringBuilder();
    Entry 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 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);
  }
}

運(yùn)行結(jié)果:

Java緩存使用如何實(shí)現(xiàn)的

FIFO

FIFO就是先進(jìn)先出,可以使用LinkedHashMap進(jìn)行實(shí)現(xiàn)。

當(dāng)?shù)谌齻€(gè)參數(shù)傳入為false或者是默認(rèn)的時(shí)候,就可以實(shí)現(xiàn)按插入順序排序,就可以實(shí)現(xiàn)FIFO緩存了。

/**
 * Constructs an empty LinkedHashMap 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 - true for
 *     access-order, false 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;
}

實(shí)現(xiàn)代碼跟上述使用LinkedHashMap實(shí)現(xiàn)LRU的代碼基本一致,主要就是構(gòu)造函數(shù)的傳值有些不同。

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class LRU1 {
  private final int MAX_CACHE_SIZE;
  private final float DEFAULT_LOAD_FACTORY = 0.75f;

  LinkedHashMap map;

  public LRU1(int cacheSize) {
    MAX_CACHE_SIZE = cacheSize;
    int capacity = (int)Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTORY) + 1;
    /*
     * 第三個(gè)參數(shù)設(shè)置為true,代表linkedlist按訪問(wèn)順序排序,可作為L(zhǎng)RU緩存
     * 第三個(gè)參數(shù)設(shè)置為false,代表按插入順序排序,可作為FIFO緩存
     */
    map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTORY, false) {
      @Override
      protected boolean removeEldestEntry(Map.Entry 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> getAll() {
    return map.entrySet();
  }

  @Override
  public String toString() {
    StringBuilder stringBuilder = new StringBuilder();
    for (Map.Entry entry : map.entrySet()) {
      stringBuilder.append(String.format("%s: %s ", entry.getKey(), entry.getValue()));
    }
    return stringBuilder.toString();
  }

  public static void main(String[] args) {
    LRU1 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);
  }
}

運(yùn)行結(jié)果:

Java緩存使用如何實(shí)現(xiàn)的

以上就是使用Java實(shí)現(xiàn)這兩種緩存的方式,從中可以看出,LinkedHashMap實(shí)現(xiàn)緩存較為容易,因?yàn)榈讓雍瘮?shù)對(duì)此已經(jīng)有了支持,自己編寫鏈表實(shí)現(xiàn)LRU緩存也是借鑒了LinkedHashMap中實(shí)現(xiàn)的思想。在Java中不只是這兩種數(shù)據(jù)結(jié)構(gòu)可以實(shí)現(xiàn)緩存,比如ConcurrentHashMap、WeakHashMap在某些場(chǎng)景下也是可以作為緩存的,到底用哪一種數(shù)據(jù)結(jié)構(gòu)主要是看場(chǎng)景再進(jìn)行選擇,但是很多思想都是可以通用的。

關(guān)于Java緩存使用如何實(shí)現(xiàn)的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。


新聞名稱:Java緩存使用如何實(shí)現(xiàn)的
瀏覽地址:http://weahome.cn/article/jpooij.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部