缓存(ehcache/guavaCache使用)

article/2025/10/4 4:51:52

单机缓存

  • ehcache:
    • 单独使用:
    • 与spring集成:
      • 编程式操作:
      • 注解式使用:
    • 与springboot集成:
  • guava cache:
    • 单独使用:
    • spring/springboot集成:
    • 自定义KeyGenerator:
  • 自定义缓存
    • 缓存应具备的功能:
    • LRU淘汰策略的实现
      • 基于LinkedHashMap实现
      • 基于LinkedList实现
    • 内存敏感能力的实现

ehcache:

实体对象,要序列化(与sring整合)

@Builder
@Data
public class User implements Serializable {private Long id;private String name;
}

单独使用:

1.引入依赖

<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>2.10.6</version>
</dependency>

2.ehcache.xml编写

<?xml version="1.0" encoding="utf-8" ?>
<ehcachexmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="https://www.ehcache.org/ehcache.xsd"><!--系统属性,C:\Users\86155\AppData\Local\Temp\默认写到磁盘的路径--><diskStore path="java.io.tmpdir"/><!--对应net.sf.ehcache.config.CacheConfigurationmemoryStoreEvictionPolicy:驱逐策略,其他值 net.sf.ehcache.store.MemoryStoreEvictionPolicyeternal:永不过期timeToIdleSeconds:eternal="false"时有效,闲置多久stimeToLiveSeconds:eternal="false"时有效,从创建开始计算,存活多久smaxElementsOnDisk:localTempSwap时有效,表示最多可以往磁盘中写多少个diskExpiryThreadIntervalSeconds:localTempSwap时有效,检查磁盘元素是否失效的时间间隔persistence: 当cache中的元素个数=maxEntriesLocalHeap时,localTempSwap写到磁盘其他值:net.sf.ehcache.config.PersistenceConfiguration.Strategystatistics="true" 开启统计--><cachename="user_cache"maxEntriesLocalHeap="1000"eternal="false"timeToIdleSeconds="600"timeToLiveSeconds="6000"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"statistics="true"><persistence strategy="localTempSwap"/></cache><!--默认--><!-- <defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><persistence strategy="localTempSwap"/></defaultCache>-->
</ehcache>

3.api使用

    /*** 单独使用ehcache的api进行编程*/@Testpublic void test1(){//定义ehcache的配置文件String absPath = "D:\java\idea\IdeaProject2\cache\echache\src\main\resources\ehcache\ehcache.xml";//根据ehcache.xml创建cacheManager,管理多个cache,user_info,item_cache...CacheManager cacheManager = CacheManager.create(absPath);//getCacheNames():获取到cacheManager管理的所有cacheString[] cacheNames = cacheManager.getCacheNames();System.out.println("获取到的cache的名字:" + Arrays.toString(cacheNames));//通过cache的名字(我们指定的)获取具体的cacheCache userCache = cacheManager.getCache("user_cache");User user = User.builder().id(123L).name("WMH").build();//往userCache中放入一个user,参数:key 对象Element element = new Element(user.getId(),user);userCache.put(element);//通过key取出 缓存的对象Element resultEle = userCache.get(123L);System.out.println("获取到的resultEle:" + resultEle);System.out.println("获取到的resultEle的Value:" + resultEle.getObjectValue());}

在这里插入图片描述

与spring集成:

ehcache与spring的集成方式:

  • 1.AnnotationConfigApplicationContext
  • 2.xml

spring的缓存抽象的方式

  • 1.编程式操作
  • 2.使用注解 如@Cacheable

序列化报错解决方式:

  • 1.不序列化到磁盘,在ehcache.xml添加配置
  • 2.序列化到磁盘:user实现序列化接口

引入spring的cache支持

<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId>
</dependency>
<!-- ehcache 相关依赖 -->
<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId>
</dependency>
<dependency><groupId>cn.pomit</groupId><artifactId>Mybatis</artifactId><version>${project.version}</version>
</dependency>

编程式操作:

1.ehcache.xml配置文件同上,配置cache信息(实体类不序列化到磁盘)

<persistence strategy="none"/>

2.spring-ehcache.xml配置文件

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:cache="http://www.springframework.org/schema/cache"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache-4.0.xsd"><!--相当于CacheManager cacheManager = CacheManager.create(absPath);根据ehcache.xml配置文件生成cacheManager--><beanid="ehCacheManager"class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><property name="configLocation" value="classpath:ehcache/ehcache.xml"/></bean><!--对原生的CacheManager进行包装,org.springframework.cache.CacheManager有多个实现--><!--实现方式一:--><bean id="ehCacheCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"><property name="cacheManager" ref="ehCacheManager"/><!--事务回滚缓存也回滚--><property name="transactionAware" value="true"/></bean><!--实现方式二:--><!--<bean id="concurrentMapCacheManager"  class="org.springframework.cache.concurrent.ConcurrentMapCacheManager"><property name="cacheNames"><list><value>user_cache</value><value>store_cache</value></list></property></bean>--><!--跟@EnableCaching一样--><cache:annotation-driven proxy-target-class="true" cache-manager="ehCacheCacheManager"/>
</beans>

3.测试使用

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:ehcache/spring-ehcache.xml"})
public class SpringEhcacheTest {@Resourceprivate CacheManager cacheManager;/*** 编程式使用*/@Testpublic void test1(){Cache userCache = cacheManager.getCache("user_cache");//往userCache中放入一个userUser user = User.builder().id(123L).name("WMH").build();//key 对象userCache.put(user.getId(),user);//获取System.out.println("获取的对象:"+userCache.get(123L,User.class));}
}

注解式使用:

1.ehcache.xml 文件同上,spring-ehcache.xml,需要注入serviceImpl,也可改为config类

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:cache="http://www.springframework.org/schema/cache"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache-4.0.xsd "><bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><property name="configLocation" value="classpath:ehcache/ehcache.xml"/></bean><bean id="concurrentMapCacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager"><property name="cacheNames"><list><value>user_cache</value><value>store_cache</value></list></property></bean><cache:annotation-driven proxy-target-class="true" cache-manager="concurrentMapCacheManager"/><bean class="com.suisui.service.impl.UserServiceImpl"/>
</beans>

2.serviceImpl实现类

@CacheConfig(cacheNames = {"user_cache"})//存放在哪个缓存里
public class UserServiceImpl implements UserService {//调用方法:看缓存有没有?有:返回缓存中的结果@Override@Cacheable(key="#id")//spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中public User getById(Long id) {System.out.println("模拟查询数据库");User user = User.builder().id(id).name("哇哈哈").build();return user;}
}

测试使用:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:ehcache/spring-ehcache.xml"})
public class SpringEhcacheTest {@Resourceprivate CacheManager cacheManager;@Resourceprivate UserService userService;/*** 注解使用,看缓存中有没有,有返回缓存中的结果,没有执行方法,并把结果放入缓存*/@Testpublic void test2(){User byId = userService.getById(3L);System.out.println("信息:"+byId);System.out.println("信息2:"+userService.getById(3L));System.out.println("信息3:"+userService.getById(3L));}}

在这里插入图片描述

与springboot集成:

ehcache与springboot整合

  • 1.在application.yml中指定ehcache的配置文件
  • 2.启动类加@EnableCaching

1.配置文件

spring:cache:ehcache:config: classpath:ehcache/ehcache.xml(同上)

2.添加注解@EnableCaching启用注解

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableCaching
public class SpringBootEhcache {public static void main(String[] args) {SpringApplication.run(SpringApplication.class,args);}
}

3.serviceImpl编写

@Service
public class UserServiceImpl implements UserService {@Overridepublic User getById(Long id) {System.out.println("模拟查询数据库");User user = User.builder().id(id).name("哇哈哈").build();return user;}
}

3.使用


@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootEhcacheTest {@Resourceprivate CacheManager cacheManager;@Resourceprivate UserService userService;@Testpublic void test1(){/*** 拿到org.springframework.cache.ehcache.EhCacheCacheManager* 就可以进行编程式的api使用*/System.out.println(cacheManager.getClass());/*** 注解式使用*/User byId = userService.getById(3L);System.out.println(byId);System.out.println(userService.getById(3L));System.out.println(userService.getById(3L));}
}

在这里插入图片描述

guava cache:

引入依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>29.0-jre</version>
</dependency>

单独使用:

单独使用guava的cache,有两种

  • 1.com.google.common.cache.LocalCache.LocalLoadingCache
    特点:缓存中获取不到值,会根据指定的loader进行加载后自动放入缓存
  • 2.com.google.common.cache.LocalCache.LocalManualCache
    特点:类似ehcache
public class LoadingCacheTest {@Testpublic void test1() throws Exception {LoadingCache<Long, User> loadingCache = CacheBuilder.newBuilder()//指定并发级别.concurrencyLevel(8)//初始化大小,配合concurrencyLevel做分段锁,提高性能.initialCapacity(60)//缓存中最多可以放多少元素.maximumSize(10)//从写入开始计算,3s以后过期,会被清除.expireAfterWrite(3, TimeUnit.SECONDS)//统计命中率.recordStats()//缓存中的元素被驱逐出去后自动回调到这里.removalListener(new RemovalListener<Long, User>() {@Overridepublic void onRemoval(RemovalNotification<Long, User> notification) {Long key = notification.getKey();RemovalCause cause = notification.getCause();System.out.println("key:" + key+",被移出缓存,原因:"+cause);}})//缓存中获取不到值,会回调到这里.build(new CacheLoader<Long, User>() {@Overridepublic User load(Long key) throws Exception {//key:将来loadingCache.get(key)获取不到传来的key//可以在这里进行数据的加载System.out.println("去存储中加载");User user = User.builder().id(key).name("哇哈哈").build();return user;}});for (long i = 0; i < 20; i++) {//get方法抛异常  loadingCache.get(i);User user = loadingCache.getUnchecked(999L);System.out.println(user);TimeUnit.SECONDS.sleep(1);}System.out.println("统计信息"+loadingCache.stats().toString());}
}

在这里插入图片描述

spring/springboot集成:

spring或者springboot集成任何第三方框架:

  • 1.xml或者在@Configuration中@bean
  • 2.springboot:stater或@Configuration中@bean注入

1.编写GuavaCacheManager

/*** 因为spring没有自带的CacheManager*/
public class GuavaCacheManager extends AbstractCacheManager {/*** 用来加载当前cacheManager管理哪些cache* @return*/@Overrideprotected Collection<? extends Cache> loadCaches() {/*** 获取所有的cache*/com.google.common.cache.Cache<Object,Object> userCache = CacheBuilder.newBuilder().maximumSize(100).build();//user_cache保证该缓存存在GuavaCache guavaUsercache = new GuavaCache("user_cache", userCache);//new GuavaCache("book_cache",bookCache);Collection<Cache> caches = new LinkedHashSet();caches.add(guavaUsercache);return caches;}
}

2.GuavaCache 编写

/***自定义cache的场景:* 1.GuavaCache* 2.应用里需要多级缓存,(1.本地缓存+redis缓存,2.自定义cache)*/
public class GuavaCache implements Cache {private String cacheName;/*** 使用组合模式持有真正的cache对象*/private com.google.common.cache.Cache<Object,Object> internalCache;public GuavaCache(String cacheName, com.google.common.cache.Cache<Object, Object> internalCache) {this.cacheName = cacheName;this.internalCache = internalCache;}@Overridepublic String getName() {return cacheName;}@Overridepublic Object getNativeCache() {return internalCache;}@Overridepublic ValueWrapper get(Object key) {Object obj = internalCache.getIfPresent(key);if(obj != null){//返回ValueWrapper的默认实现return new SimpleValueWrapper(obj);}return null;}@Overridepublic <T> T get(Object key, Class<T> aClass) {throw new RuntimeException("参考get实现");}@Overridepublic <T> T get(Object key, Callable<T> callable) {throw new RuntimeException("参考get实现");}@Overridepublic void put(Object key, Object value) {internalCache.put(key,value);}/*** 逐出单个* @param key*/@Overridepublic void evict(Object key) {//这里如果是多级缓存,需要完成本地缓存和分布缓存的同步逻辑//比如mqinternalCache.invalidate(key);}@Overridepublic void clear() {internalCache.invalidateAll();}
}

3.spring-guava-cache.xml

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:cache="http://www.springframework.org/schema/cache"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache-4.0.xsd"><bean id="guavaCacheManager" class="com.suisui.guava.GuavaCacheManager"></bean><cache:annotation-driven proxy-target-class="true" cache-manager="guavaCacheManager"/><bean class="com.suisui.service.impl.UserServiceImpl"/>
</beans>

4.UserServiceImpl编写

@Service
@CacheConfig(cacheNames = {"user_cache"})
public class UserServiceImpl implements UserService {/*** 调用方法:看缓存有没有?有:返回缓存中的结果*/@Override@Cacheable(key="#id")//spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中public User getById(Long id) {System.out.println("模拟查询数据库");User user = User.builder().id(id).name("哇哈哈").build();return user;}}

5.测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:guava/spring-guava-cache.xml"})
public class SpringGuavaCacheTest {@Resourceprivate GuavaCacheManager cacheManager;@Resourceprivate UserService userService;/*** 测试自定义CacheManager* 1.编写GuavaCache* 2.编写GuavaCacheManager* 3.配置spring-guava-cache.xml*/@Testpublic void test1(){System.out.println(cacheManager.getClass());User byId = userService.getById(3L);System.out.println(byId);System.out.println(userService.getById(3L));System.out.println(userService.getById(3L));}
}

在这里插入图片描述

自定义KeyGenerator:

1.编写MyKeyGenerator

/*** 缓存的key,使用spel书写* 1.有时候参数写的比价麻烦* 2.都要写key对应的表达式,可能会忘记写* 3.不写使用配置的keyGenerator,写了以写的为准*/
public class MyKeyGenerator implements KeyGenerator {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder finalKey = new StringBuilder();//方法全限定名finalKey.append(target.getClass().getName()).append(".").append(method.getName()).append(".");if(params == null || params.length == 0){return finalKey.append(0).toString();}for(Object param :params){if(param == null){finalKey.append("null");}else if(ClassUtils.isPrimitiveArray(param.getClass())){//一个参数为int[] 等八种基本类型组成数组,不包含包装类int length = Array.getLength(param);for (int i = 0; i < length; i++) {finalKey.append(Array.get(param,i)).append(",");}}else if(ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String){//isPrimitiveOrWrapper:true:八种基本类型+void+8种基本类型的包装类型+字符串finalKey.append(param);}else{//序列化String paramStr = JSON.toJSONString(param);//对字符串生成hashlong murmurHash = Hashing.murmur3_128().hashString(paramStr, StandardCharsets.UTF_8).asLong();finalKey.append(murmurHash);}//分隔多个参数finalKey.append("-");}System.out.println("最终的Key: "+finalKey);return finalKey;}
}

2.spring-guava-cache.xml(指定KeyGenerator)

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:cache="http://www.springframework.org/schema/cache"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache-4.0.xsd"><bean id="guavaCacheManager" class="com.suisui.guava.GuavaCacheManager"></bean><bean id="keyGenerator" class="com.suisui.key.MyKeyGenerator"></bean><cache:annotation-driven proxy-target-class="true" cache-manager="guavaCacheManager" key-generator="keyGenerator"/><bean class="com.suisui.service.impl.UserServiceImpl"/>
</beans>

3.UserServiceImpl编写

@Service
@CacheConfig(cacheNames = {"user_cache"})
public class UserServiceImpl implements UserService {/***key遵循spring的spel语法,1.有时候参数写的比价麻烦2.都要写key对应的表达式*/@Override@Cacheablepublic User getUser(User queryParam, int[] arr,String str) {System.out.println("模拟查询数据库--测试自定义keyGenerator");User user = User.builder().id(99L).name("java 数据").build();return user;}
}

4.测试自定义keyGenerator

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:ehcache/spring-guava-cache.xml"})
public class SpringGuavaCacheTest {@Resourceprivate GuavaCacheManager cacheManager;@Resourceprivate UserService userService;/*** 测试自定义的keyGenerator*/@Testpublic void test2(){User queryParam = User.builder().id(66L).name("碎金").build();int[] arr = new int[2];arr[0] = 1;arr[1] = 2;String str = "abc";User user = userService.getUser(queryParam, arr,str);System.out.println(user);System.out.println(userService.getUser(queryParam, arr,str));System.out.println(userService.getUser(queryParam, arr,str));}
}

在这里插入图片描述

自定义缓存

缓存应具备的功能:

1.最大能放多少个,溢出淘汰的机制:FIFO,LRU,LFU

  • 淘汰最先放入缓存的数据,即FIFO(First In First Out)
  • 淘汰最久未使用的数据,即 LRU(Least Recently Used)
  • 淘汰使用频率低的数据,即LFO(Least Frequently Used)

2.过期需要清除
3.内存敏感(不能因为缓存的原因导致业余程序的OOM)
4.线程的安全
5.统计命中率
6.序列化扩展

LRU淘汰策略的实现

基于LinkedHashMap实现

LinkedHashMap测试:

 @Testpublic void test1(){/*int initialCapacity, 初始大小*float loadFactor,载荷系数boolean accessOrder  设为true,根据访问时间排序*/// LinkedHashMap会根据访问时间动态排序LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(16,0.75f,true);linkedHashMap.put("a","a_value");linkedHashMap.put("b","b_value");linkedHashMap.put("c","c_value");System.out.println(linkedHashMap);String bValue = linkedHashMap.get("b");System.out.println("b的值:" + bValue);System.out.println(linkedHashMap);}

在这里插入图片描述
1.缓存功能接口

/*** 定义基本的缓存功能接口*/
public interface Cache {void put(Object key,Object value);void remove(Object key,Object value);void clear();Object get(Object key);int size();
}

2.基于LinkedHashMap实现缓存:

public class CacheVersion1 implements Cache {//缓存容量private int capacity;//通过组合关系持有一个内部的真正缓存对象private InternalCache internalCache;public CacheVersion1(int capacity) {this.capacity = capacity;internalCache = new InternalCache(capacity);}private static class InternalCache extends LinkedHashMap<Object,Object>{private int capacity;public InternalCache(int capacity) {super(16,0.75f,true);this.capacity = capacity;}/***在java.util.LinkedHashMap#afterNodeInsertion(boolean)回调* @param eldest* @return true:清除排在最前面的元素,false不清除*/@Overrideprotected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {return size() > capacity;}}@Overridepublic void put(Object key, Object value) {internalCache.put(key,value);}@Overridepublic void remove(Object key, Object value) {internalCache.remove(key,value);}@Overridepublic void clear() {internalCache.clear();}@Overridepublic Object get(Object key) {return internalCache.get(key);}@Overridepublic int size() {return internalCache.size();}@Overridepublic String toString() {return "CacheVersion1{" +"capacity=" + capacity +", internalCache=" + internalCache +'}';}
}

3.测试

    @Testpublic void test2(){CacheVersion1 cache = new CacheVersion1(3);cache.put("a","a_value");cache.put("b","b_value");cache.put("c","c_value");System.out.println(cache);//演示访问一次,改变排序String bValue = (String)cache.get("b");System.out.println("b的值:"+bValue);//重新排序System.out.println(cache);}

在这里插入图片描述

基于LinkedList实现

缓存接口同上,基于LinkedList实现缓存:

/*** 基于linkedList实现LRU驱逐算法*/
public class CacheVersion2 implements Cache {//缓存容量private int capacity;//用来维护缓存key的顺序private LinkedList<Object> keyList;//通过组合关系持有一个内部的真正缓存对象private Map<Object,Object> internalCache;public CacheVersion2(int capacity) {this.capacity = capacity;internalCache = new HashMap<>();keyList = new LinkedList<>();}@Overridepublic void put(Object key, Object value) {//调用put此方式时,已存在的元素个数==容量if(size() == capacity){//移除第一个(get()中设置,最后访问的在最后)Object firstKey = keyList.removeFirst();internalCache.remove(firstKey);}//加入当前keykeyList.addLast(key);internalCache.put(key,value);}@Overridepublic void remove(Object key, Object value) {keyList.remove(key);internalCache.remove(key,value);}@Overridepublic void clear() {keyList.clear();internalCache.clear();}@Overridepublic Object get(Object key) {//true:key存在,false:key在keyList中不存在boolean removeResult = keyList.remove(key);if(removeResult){Object value = internalCache.get(key);//把现在访问的key排序,最后访问的放在最后keyList.addLast(key);return value;}return null;}@Overridepublic int size() {//sinternalCache.get(key)return keyList.size();}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();for (Object key : keyList) {sb.append("key").append(key).append(",").append("value:").append(internalCache.get(key)).append("-");}return sb.toString();}
}

测试:

    @Testpublic void test3(){CacheVersion2 cache = new CacheVersion2(3);cache.put("a","a_value");cache.put("b","b_value");cache.put("c","c_value");System.out.println(cache);//演示访问一次,改变排序String bValue = (String)cache.get("b");System.out.println("b的值:"+bValue);//重新排序System.out.println(cache);cache.put("d","d_value");System.out.println(cache);}

在这里插入图片描述

内存敏感能力的实现

强引用:只要有引用就不会被回收,基本OOM
软引用:gc且堆内存吃紧时才会被回收(适合)
弱引用:每次gc都会被回收
虚引用:随时都有可能被回收

  /*测试强引用OOM*/@Testpublic void test() throws InterruptedException {CacheVersion1 cache = new CacheVersion1(99999);for (int i = 1; i < Integer.MAX_VALUE; i++) {Dept dept = new Dept((long)i);cache.put(dept.getId(),dept);TimeUnit.SECONDS.sleep(1);}}

设置参数:
在这里插入图片描述
结果:
在这里插入图片描述
内存敏感实现(get()/put()):

/*** 基于linkedHashMap实现LRU驱逐算法+内存敏感*/
public class CacheVersion1final implements Cache {//缓存容量private int capacity;//通过组合关系持有一个内部的真正缓存对象private InternalCache internalCache;public CacheVersion1final(int capacity) {this.capacity = capacity;internalCache = new InternalCache(capacity);}private static class InternalCache extends LinkedHashMap<Object,Object>{private int capacity;public InternalCache(int capacity) {super(16,0.75f,true);this.capacity = capacity;}/***在java.util.LinkedHashMap#afterNodeInsertion(boolean)回调* @param eldest* @return true:清除排在最前面的元素,false不清除*/@Overrideprotected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {return size() > capacity;}}@Overridepublic void put(Object key, Object value) {SoftReference<Object> softReference = new SoftReference<>(value);internalCache.put(key,softReference);}@Overridepublic void remove(Object key, Object value) {internalCache.remove(key,value);}@Overridepublic void clear() {internalCache.clear();}@Overridepublic Object get(Object key) {Object o = internalCache.get(key);if(o == null){return null;}SoftReference<Object> softReference = (SoftReference<Object>) o;//返回引用的真实对象return softReference.get();}@Overridepublic int size() {return internalCache.size();}@Overridepublic String toString() {return "CacheVersion1{" +"capacity=" + capacity +", internalCache=" + internalCache +'}';}
}

测试弱引用:

    /*测试软引用内存敏感*/@Testpublic void test5() throws InterruptedException {CacheVersion1final cache = new CacheVersion1final(99999);for (int i = 1; i < Integer.MAX_VALUE; i++) {System.out.println("放入第"+i+"个");Dept dept = new Dept((long)i);cache.put(dept.getId(),dept);}}

在这里插入图片描述


http://chatgpt.dhexx.cn/article/VR2BP7rO.shtml

相关文章

iOS 缓存框架YYCache学习

文章目录 前言一、YYCache的来源二、YYCache的结构1. YYMemoryCache1.1 最近最少使用—LRU(Least Frequently Used)1.2 基于LRU的增删改查1.2.1 增加数据1.2.2 删除数据1.2.3 查找修改数据1.2.4 YYMemoryCache的增删改查 2.YYDiskCache 总结参考文章 前言 提示&#xff1a;这篇…

深入理解YYCache缓存策略

文章目录 前言几个主要成员类1 YYCache2 YYMemoryCache3 YYDiskCache 实例化1 实例方法2 构造器方法 查1 检查是否有缓存2 读缓存 增1 写内存缓存2 写磁盘缓存 删1 清空内存缓存2 清空磁盘缓存 YYMemoryCache 初始化做了什么总结本文完 前言 YYCache是著名iOS框架YYKit的一个组…

Unity OnDestroy 调用

Test Code private GameObject _temp;_temp Instantiate(Resources.Load("gameObject original"), parent) as GameObject;if (Input.GetMouseButtonDown(1)) {Destroy(_temp);_temp null; }试验结果&#xff08;场景中本来存在的gameObjec或Resources出来的game…

报错原因高的地图调用mapView.onDestroy() 崩溃问题

以前在android app中使用地图的项目需要使用高德地图。 按照高德地图的开发文档创建测试项目&#xff0c;导入依赖&#xff0c;很快就成功显示了地图&#xff0c;然后在退出地图Activity时&#xff0c;app立即崩溃&#xff0c;通过追踪&#xff0c;发现是在销毁地图时出现崩溃…

Android跨进程通信Client Crash后Server端onDestroy

hi&#xff0c;粉丝朋友大家好&#xff01; 好久没有给大家写blog了&#xff0c;哈哈&#xff0c;这里说声抱歉&#xff01;实在家里比较忙&#xff0c;今天就来给大家分享一个跨进程专题课中学员问的一个问题&#xff0c;blog就来解答一下这个问题。 问题背景&#xff1a; 视频…

Activity onDestroy延迟回调

前端时间工作的时候遇到了两个奇怪的问题&#xff1a; 使用百度步行导航的时候&#xff0c;开启导航后立即退出&#xff0c;再次进入的时候就会黑屏&#xff1b;使用度小满支付的时候&#xff0c;当支付成功后页面一直显示loading&#xff0c;过了10s左右才恢复正常。 这看似…

基于MFC的OpenDDS发布订阅例子(PubSubDemo)

在编译完成Message.idl,产生MessageCommon.dll和相应的MessageTypeSupport的.h头文件和.cpp文件(MessageTypeSupportImpl.h、MessageTypeSupportC.h)的基础上,新建PubSubDemo.sln和工程PubSubDemo.vcxproj,并开始编码,实现基于Message的发布和订阅流程。 1)新建基于Dia…

OPenDDS程序 的 实现+运行

标题DDS程序实现和运行 本文记录了Windows10环境下OpenDDS环境搭建&#xff0c;idl自定义&#xff0c;代码生成&#xff0c;代码编写的全过程。 一、环境搭建 1.详细情况请参考开发笔记&#xff1a;1. OpenDDS环境搭建-Windows 10.note 编译好后生成了两个文件夹“OpenDDS-3.…

OpenDDS-1

转自&#xff1a;软件开发.OpenDDS 设计智能座舱时ECU之间通信及与TSP通信选择使用OpenDDS是可以的&#xff0c;因此不少人都认为OpenDDS是属于汽车以太网&#xff08;Aumotive Ethernet&#xff0c;AE&#xff09;&#xff0c;但事实上autosar AE中定义中有SomeIP、DoIP、AVB…

Java程序调用OpenDDS

一、前言 前面我们用三篇博客介绍了 OpenDDS在WIndows上的环境配置 Windows下的OpenDDS编译&#xff08;超详细&#xff09;_山中野竹的博客-CSDN博客_opendds windows 三种方式运行发布订阅示例程序 OpenDDS运行示例&#xff08;Messenger&#xff09;程序_山中野竹的博客-C…

OpenDDS运行实例

因为OpenDDS是分布式的部署&#xff0c;所以一般发布端和订阅端都不在同一台电脑上。 我在同一台电脑上进行测试&#xff0c;所以ip地址为&#xff1a;127.0.0.1 1.发布端 1.1 新建ior文件 在根目录先新建repo.ior文件&#xff1a; IOR:010000001e00000049444c3a4f70656e44…

Java调用OpenDDS(1)-编译安装openDDS-补上了所有网络上其他文章遗漏的细节

Java调用OpenDDS过程中踩了很多坑&#xff0c;记录一下。 提纲 1、DDS简介 2、DDS协议的实现产品 3、OpenDDS安装过程 1、DDS简介 DDS指的是Data Distribution Service&#xff0c;也即数据分发服务&#xff0c;是OMG&#xff08;Object Management Group&#xff0c;对象管理…

OpenDDS自学

前言 最近做毕设要做一个DDS系统和TISA系统的网关&#xff0c;完全没有基础&#xff0c;只好对着OpenDDS的Developers’ Guide和《分布式系统实时发布/订阅数据分发技术》这本书一点一点学(顺便吐槽这本书就是guide的翻译版&#xff0c;很多语句不通)。遇到很多问题&#xff0…

VS2015编译OpenDDS

最近需要研究下OpenDDS,因此需要搭建个环境&#xff0c;下面是一点经验&#xff0c;大家可以参考。 使用版本是OpenDDS-3.12、ACETAO-6.5.10和strawberry-perl&#xff0c;之所以使用ACETAO-6.5.10是因为往后的版本没有现成的2015对应的sln了。 一.资源下载 1.可以直接使用我…

Java调用OpenDDS(2)-理解OpenDDS自带的Messager示例

OpenDDS安装好之后&#xff0c;下一步就是利用OpenDDS来开发通信项目了。不过在项目中应用OpenDDS之前&#xff0c;先消化一下OpenDDS安装包中自带的示例项目messenger&#xff0c;通过阅读messenger的源代码来熟悉一下OpenDDS提供的用来开发Java项目的类。 提纲 1、准备工作 2…

OpenDDS

OpenDDS简介 Don Busch&#xff0c;首席软件工程师兼合作伙伴 Object Computing&#xff0c;Inc.&#xff08;OCI&#xff09; 介绍 分布式实时应用程序有时以数据为中心而不是以服务为中心&#xff0c;这意味着分布式系统中参与者的主要目标是分发应用程序数据&#xff0c;而…

OpenDDS系列(3) —— 第一个OpenDDS程序

文章目录 [toc]3.1 发送数据3.2 项目3.2.1 主题3.2.2 Publisher&#xff08;发布者&#xff09;3.2.3 Subscriber&#xff08;订阅者&#xff09; 3.3 在Windows上构建3.4 在Linux上构建3.4.1 运行 3.5 结论 3.1 发送数据 我们将创建一个主题&#xff0c;这是一个通过DDS交换数…

OpenDDS学习笔记(2):DDS概述

文章目录 一、DDS体系结构1.1 DLRL层1.2 DCPS层 二、DDS通信过程三、DDS通信特点四、DDS标准实现4.1 RTI DDS软件4.2 OpenSplice DDS软件4.3 OpenDDS软件 一、DDS体系结构 DDS采用DCPS通信机制&#xff0c;提供一个与平台无关的数据模型。它允许应用程序实时发布拥有的信息&am…

OpenDDS系列(1) —— OpenDDS 简介

1. OpenDDS简要介绍 1.1 简介 1.1.1 DDS是什么1.1.2 DDS通信的基本要素1.1.3 DDS架构的主要优点1.1.4 DDS产品种类1.1.5 OpenDDS 1.2 DDS的应用领域 美国海上战争中心(NSWC)高性能分布式计算系统&#xff08;HiPer-D&#xff09; 1.3 结论 1. OpenDDS简要介绍 1.1 简介 1.1.…

IDEA中查找与替换快捷键(项目全局替换、该文件下替换)

该文件下查找&#xff08;CtrlF&#xff09; 项目全局查找&#xff08;CtrlShiftF 或【Edit】——>【Find】——>【Find in Path…】&#xff09; 注意&#xff1a;本人电脑上的IDEA版本不支持该快捷键&#xff08;CtrlShiftF&#xff09;&#xff0c;有可能是快捷键冲突…