Guava缓存器源码分析——删除消息
Guava缓存器的删除消息机制测试代码——
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() .maximumSize(3) .expireAfterWrite(10, TimeUnit.SECONDS) .recordStats() .removalListener(new RemovalListener<String, Integer>() { @Override public void onRemoval(RemovalNotification<String, Integer> rn) { System.out.println(rn.getKey() + "被移除"); } }) .build( new CacheLoader<String, Integer>() { @Override public Integer load(String key) throws Exception { return num++; //初始值为1; } }); try { System.out.println(cache.get("a")); System.out.println(cache.get("b")); System.out.println(cache.get("c")); System.out.println(cache.get("d")); System.out.println(cache.get("e")); } catch (ExecutionException e) { e.printStackTrace(); }测试结果: 因为缓存大小为3,依次查询到c时,缓存已满,当查询d时,a将被移除,当查询e时,b将被移除。 CacheBuilder的removalListener方法中,将其监听器参数赋值给成员变量removalListener,在LocalCache构造函数中,又传给LocalCache的删除监听器removalListener。至于removalNotificationQueue,也在LocalCache构造函数初始化:new ConcurrentLinkedQueue<RemovalNotification<K, V>>()。
void processPendingNotifications() { RemovalNotification<K, V> notification; while ((notification = removalNotificationQueue.poll()) != null) { try { removalListener.onRemoval(notification); } catch (Throwable e) { logger.log(Level.WARNING, "Exception thrown by removal listener", e); } } }该函数被调用的过程如下:
processPendingNotifications ←runUnlockedCleanup ←cleanUp(清零readCount) ←postReadCleanup(readCount增1) ←postWriteCleanup只要涉及键值的读操作,都将执行postReadCleanup操作,每次执行postReadCleanup操作时readCount都增1,当其达到64时(DRAIN_THRESHOLD为0x3F,即0011 1111),引发cleanUp操作。
if ((readCount.incrementAndGet() & DRAIN_THRESHOLD) == 0) { cleanUp(); }而只要涉及键值的写操作,都将执行postWriteCleanup操作。