Caches

設定:

1. maximumSize(long) weigher(Weigher) maxumumWeigher(long)

2. expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)

3. weakKeys() weakValues() softValues()

4. invalidate(key) invalidateAll(keys) invalidateAll()

5. removalListener(RemovalListener)

Refresh:

1. LoadingCache.refresh(K)

2. CacheLoader.reload(K, V)

3. CacheBuilder.refreshAfterWrite(long, TimeUnit)

使い方1:Callable callback (Cache)

import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;

import com.google.common.cache.CacheBuilder;

Cache<String, String> cache =

CacheBuilder.newBuilder()

.maximumSize(100)

.expireAfterAccess(3, TimeUnit.SECONDS)

.expireAfterWrite(6, TimeUnit.SECONDS)

.build();

あるいは

String spec = "maximumSize=100,expireAfterAccess=3s,expireAfterWrite=6s";

Cache<String, String> cache = CacheBuilder.from(spec).build();

cache.put("key", "value");

String value = cache.getIfPresent("key");

cache.invalidate("key"); // 削除

cache.invalidateAll(); // 全削除

String result = cache.get("key", new Callable<String>() {

public String call() {

return ...;

}

});

使い方2:CacheLoader (LoadingCache)

import java.util.concurrent.ExecutionException;

import com.google.common.cache.LoadingCache;

import com.google.common.cache.CacheBuilder;

import com.google.common.cache.CacheLoader;

private static String getValue(String key) {

try {

TimeUnit.SECONDS.sleep(3); // 重い処理

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

return "value";

}

LoadingCache<String, String> cache =

CacheBuilder.newBuilder()

.maximumSize(100)

.softValues() //メモリ不足の場合、値がGCの対象になる

.expireAfterAccess(3, TimeUnit.SECONDS)

.expireAfterWrite(6, TimeUnit.SECONDS)

.build(new CacheLoader<String, String>() {

public String load(String key) throws Exception {

return getValue(key);

}

});

try {

String value = cache.get("key"); //ロードと取得が同時に行う

//String value = cache.apply("key");

value = cache.get("key"); //2回目から速くなる

cache.put("xxx", "yyy");

} catch (ExecutionException e) {

...

}

サンプル

@Singleton

public class UserCache {

@Inject

private UserCacheLoader loader;

@Inject

private UserRemovalListener listener;

private final LoadingCache<String, Optional<User>> cache;

public UserCache() {

cache = CacheBuilder.newBuilder()

.maximumSize(100)

.expireAfterWrite(1, TimeUnit.DAYS)

.refreshAfterWrite(5, TimeUnit.SECONDS)

.removalListener(listener)

.build(loader);

}

public Optional<User> getUser(String userId) {

return cache.getUnchecked(userId);

}

}

public class UserCacheLoader

extends CacheLoader<String, Optional<User>>{

@Inject

private UserDAO userDAO;

@Override

public Optional<User> load(String userId) throws Exception {

return loadCache(userId);

}

private Optional<User> loadCache(String userId) {

User user = userDAO.getUserById(userId);

return Optional.fromNullable(user);

}

}

public class UserRemovalListener

implements RemovalListener<String, Optional<User>>{

Logger logger =

LoggerFactory.getLogger(UserRemovalListener.class);

@Override

public void onRemoval(

RemovalNotification<String, Optional<User>> notification) {

logger.info("User (" + notification.getKey()+ ") is removed.");

}

}