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.");
}
}