2. java缓存-进程内缓存

版权声明:转载请标明来源 https://blog.csdn.net/u010652576/article/details/82590958

#进程内缓存
进程内缓存的概述就不说了,可以查看:java缓存概述
本篇文章主要说说常见的进程内缓存,这里分为两类:自定义进程内缓存、轻量级进程内缓存框架。

##自定义进程缓存

利用java的基本数据结构List、Map、Set等,自定义一个缓存对应。
自定义进程缓存示例:

import java.util.HashMap;

public class MyCache {
	//测试代码
    public static void main(String[] args) {

        CustomCache cache = CustomCache.instance();

        cache.put("2313", 13213);
        cache.put("jkf1", 132);

        System.out.println(cache.get("jkf"));

        System.out.println(cache.get("jkf1"));
    }

}
//自定义缓存示例,单利必须是要保证的
class CustomCache<V> {
    private static CustomCache instance = new CustomCache();


    private HashMap<String, V> cache = new HashMap<>();

	private CustomCache(){}
     
    public static CustomCache instance() {

        return instance;

    }


    public void put(String key, V t) {

        this.cache.put(key, t);

    }


    public V get(String key) {

        return cache.get(key);

    }

}

上述自定义示例,就是简单的包装一个HahMap,对频繁访问的数据进行缓存。自定义缓存存在如下的缺点:

  1. 多线程并发访问。
  2. 存储数据过多,存在内存溢出,即没有缓存淘汰策略。
  3. 一些缓存的统计数据无法提供。
    当然上述缺陷,我们都可以在上述代码上,进行精细化开发,解决上述的缺点,但是这样的开发量比较大,与初衷背离:我只是想简简单单的使用一下,不想再开发一个专业的缓存。

轻量级进程内缓存框架

主要是说google的guava cache,这个轻量级的线程内缓存。

###使用guava cache
a. 引入方便,只需要引用google开源java类库即可,guava cache只是其中的一个包。

b. 使用简洁,Guava cache对泛型具有良好的支持,支持多种类型的缓存。例如:
String=Object,Integer=Object。

c. 不需要配置文件,直接通过代码配置缓存的各种参数,例如:并发线程量(concurrencyLevel,写的线程数)、容器初始容量(initialCapacity)、缓存移除通知(removalListener)、缓存不命中的加载数据方法(CacheLoader的load)、缓存失效策略(expireAfterWrite、maximumSize(LRU)),当然上述方法中“缓存不命中的加载数据方法”只有特殊的缓存实例支持。

d. 最特殊的:guava cache 是单线程,guava cache不会创建线程来维护缓存。

###使用示例
guava cache的缓存实例类型有多种,这里只是简单的介绍“可加载缓存(LoadingCache)”的使用,其他类型的缓存实例,请看下一篇专门的guava cache架构分析。

通过时间失效进行缓存淘汰

public static void main(String[] args) {
        LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
		        //缓存失效策略:写后30分钟
                .expireAfterWrite(30L, TimeUnit.MINUTES)
                //缓存未命中的策略:通过load方法查询获取数据
                .build(new CacheLoader<String, Integer>() {
                    @Override
                    public Integer load(String key) throws Exception {
                        return new Random().nextInt(10);
                    }

                });

    } 

更完善的示例

public static void main(String[] args) {
        LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
                .concurrencyLevel(8)
                .initialCapacity(10)
                .maximumSize(100)
                .recordStats()
                .removalListener(new RemovalListener<String, Integer>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, Integer> notification) {
                    }
                }).build(new CacheLoader<String, Integer>() {
                    @Override
                    public Integer load(String key) throws Exception {
                        return new Random().nextInt(10);
                    }
                });
    }

###什么时候使用guava cache
使用场景

  1. 你愿意消耗一些内存空间来提升速度。
  2. 你预料到某些键会被查询一次以上。
  3. 缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不能把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Memcached这类工具)
  4. guava cache可以缓存 少量的 频繁查询 的数据。
  5. guava cache的缓存失效,并不是立刻失效,而是延迟失效,原因:guava cache并不会启动线程,而是利用利用当前线程,进行缓存失效处理,例如会在写操作后调用缓存清理,如果写操作太少会在读操作进行缓存清理。当然如果对缓存清理要求严格,可以自己创建维护线程,进行缓存清理工作,例如:定时任务、其他线程
  6. 因为使用的是缓存,所以需要考虑缓存一致性对需求的要求。
  7. 因为是进程内缓存,guava cache没有提供缓存的持久化。
  8. Guava cache可以根据不同的业务设置不同的cache,可以做到同一业务的同一处理,但是又会引发缓存的离散,这个需要衡量。

guava cache的框架分析,见下一篇

猜你喜欢

转载自blog.csdn.net/u010652576/article/details/82590958