缓存模式【其他模式】

缓存模式

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);
    }
}

猜你喜欢

转载自www.cnblogs.com/zhuxudong/p/10225869.html
今日推荐