快取模式【其他模式】
阿新 • • 發佈:2019-01-05
快取模式
public class Cache { /** * Caching Pattern【快取模式】 * readThrough:先嚐試從快取中讀取資料,如果存在,則直接返回快取中的資料;如果不存在,則從資料來源載入, * 資料來源中存在目標物件,則將其寫入快取,並返回載入的物件。 * writeThrough:先將目標物件寫入資料來源,再將其寫入快取中 * writeAround:先將目標物件寫入資料來源,則將快取失效 * writeBehind:如果快取已滿 && 目標物件不再快取中,則將 LRU 物件從快取中移除,並非同步將其寫入資料來源中, * 同時將目標物件寫入快取中。 * cacheAside:readThrough && writeAround */ @Test public void all() { final CacheStore store = new CacheStore(); final long id = 1L; store.writeThrough(User.of(id, "zxd")); final User user = store.readThrough(id); store.writeAround(user); store.readThrough(id); store.writeBehind(User.of(2L, "princess")); } } @Value(staticConstructor = "of") class User { private Long id; private String name; } class LruCache<K, V> extends LinkedHashMap<K, V> { private static final long serialVersionUID = 3409436250531011182L; private final int maxSize; public LruCache(int maxSize) { super(16, 0.75F, true); this.maxSize = maxSize; } public Entry<K, V> removeEldest() { final Entry<K, V> entry = entrySet().iterator().next(); if (Optional.ofNullable(entry).isPresent()) { remove(entry.getKey()); } return entry; } public boolean isfull() { return maxSize >= size(); } } class DataSource { private static ConcurrentMap<Long, User> users = new ConcurrentHashMap<>(); public static User load(Long id) { return users.get(id); } public static void persist(User user) { users.put(user.getId(), user); } } @Slf4j class CacheStore { LruCache<Long, User> cache = new LruCache<>(1); public User readThrough(Long id) { User user; // 1)首先嚐試從快取中讀取,如果存在則直接返回 if (Optional.ofNullable(user = cache.get(id)).isPresent()) { log.info("get from cache {}", user.getId()); return user; } // 2)如果快取中不存在,則從資料來源讀取,如果讀取到值,則將其寫入快取中 final User load = DataSource.load(id); Optional.ofNullable(load).ifPresent(u -> { log.info("load data from dataSource and set cache {}", u.getId()); cache.put(u.getId(), u); }); // 返回讀取的結果 return load; } public void writeThrough(User user) { // 1)將目標物件持久化到資料來源 DataSource.persist(user); // 2)將其更新到快取中 cache.put(user.getId(), user); log.info("update dataSource and set cache{}", user.getId()); } public void writeAround(User user) { // 1)將目標物件持久化到資料來源 DataSource.persist(user); // 2)使得快取失效【即將其從快取中移除】 cache.remove(user.getId()); log.info("update dataSource and invalid cache {}", user.getId()); } public void writeBehind(User user) { // 1)如果快取已滿 && 目標值未在快取中 && LRU移除快取並將其持久化到資料來源中 if (cache.isfull() && !cache.containsKey(user.getId())) { final Entry<Long, User> entry = cache.removeEldest(); final User value = entry.getValue(); log.info("async update dataSource {}", value.getId()); // 非同步將資料寫入資料來源 CompletableFuture.runAsync(() -> { DataSource.persist(value); }); } // 2)將目標物件更新到快取中 cache.put(user.getId(), user); } public User readAside(Long id) { return readThrough(id); } public void writeAside(User user) { writeAround(user); } }