Hello @ben-manes
When I create a cache with maximumSize=1, add an removalListener. But the size-based eviction policy didn't work, the former key/value still hold, and it didn't trigger the removalListener, what I expect is that the listener should be triggered 9 times from 0 to 8.
Did I use Caffeine with wrong way? Here the code and output.
public static void main(String[] args) throws Exception {
Cache cache = Caffeine.newBuilder()
.maximumSize(1L)
.removalListener((key, value, cause) -> {
try {
System.out.println(String.format("remove, key: %s value: %s cause: %s", key, value, cause));
TimeUnit.MINUTES.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
})
.build();
for (int i = 0; i < 10; i++) {
cache.put(i + "", i);
}
System.out.println("cache size: " + cache.estimatedSize());
System.out.println("key 9 value: " + cache.getIfPresent("9"));
System.out.println("key 8 value: " + cache.getIfPresent("8"));
System.out.println("key 7 value: " + cache.getIfPresent("7"));
System.out.println("cache: " + cache.asMap());
}
And the output is:
cache size: 10
key 9 value: 9
key 8 value: 8
key 7 value: 7
cache: {0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 9=9}
remove, key: 6 value: 6 cause: SIZE
remove, key: 7 value: 7 cause: SIZE
remove, key: 8 value: 8 cause: SIZE
But with Guava Cache, the behavior is right for me.
public static void main(String[] args) throws IOException, ExecutionException {
Cache cache = CacheBuilder.newBuilder()
.maximumSize(1L)
.removalListener(n -> {
System.out.println(String.format("key: %s value: %s cause: %s", n.getKey(), n.getValue(), n.getCause()));
try {
TimeUnit.MILLISECONDS.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
})
.build();
for (int i = 0; i < 10; i++) {
cache.put(i + "", i);
}
System.out.println("size: " + cache.asMap().size());
System.out.println("key9 value: " + cache.getIfPresent("9"));
System.out.println("key8 value: " + cache.get("8", () -> "222222222"));
System.out.println("key7 value: " + cache.getIfPresent("7"));
System.out.println("cache: " + cache.asMap());
}
And the output is
remove, key: 0 value: 0 cause: SIZE
remove, key: 1 value: 1 cause: SIZE
remove, key: 2 value: 2 cause: SIZE
remove, key: 3 value: 3 cause: SIZE
remove, key: 4 value: 4 cause: SIZE
remove, key: 5 value: 5 cause: SIZE
remove, key: 6 value: 6 cause: SIZE
remove, key: 7 value: 7 cause: SIZE
remove, key: 8 value: 8 cause: SIZE
size: 1
key9 value: 9
remove, key: 9 value: 9 cause: SIZE
key8 value: loading value
key7 value: null
cache: {8=loading value}
By default we defer all work to ForkJoinPool.commonPool, whereas Guava does it on the calling thread. If you set executor(Runnable::run) then you鈥檒l see the same behavior as Guava.
Many of the behavior differences are described in the migration guide
https://github.com/ben-manes/caffeine/wiki/Guava
Thanks, the wiki helps.
Most helpful comment
By default we defer all work to
ForkJoinPool.commonPool, whereas Guava does it on the calling thread. If you setexecutor(Runnable::run)then you鈥檒l see the same behavior as Guava.