Eug*_*ene 8 java concurrency concurrenthashmap java-17
对我来说,要为此给出一个合适的标题很复杂。但一个例子应该会让事情变得简单得多。假设我有这个:
final class Cache {
private static final ConcurrentHashMap<String, List<String>> CACHE = ...
static List<String> byName(String name) {
return CACHE.computeIfAbsent(name, x -> // some expensive operation)
}
}
Run Code Online (Sandbox Code Playgroud)
这个想法可能很简单,它充当 LoadingCache,很像番石榴或咖啡因(实际上它更复杂,但这与问题无关)。
我希望能够判断这是第一次加载到缓存中,还是读取现有映射。目前,我这样做:
final class Cache {
private static final ConcurrentHashMap<String, List<String>> CACHE = ...
static List<String> byName(String name) {
boolean b[] = new boolean[1];
List<String> result = CACHE.computeIfAbsent(name, x -> {
b[0] = true;
// some expensive operation)
});
if(b[0]) {
// first load into the cache, do X
} else {
// do Y
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
这可行,但我担心我缺少一些ConcurrentHashMap可以为我提供的东西,让我可以做同样的事情。谢谢。
如果您想避免单元素数组将数据传递出 lambda(我宁愿使用 or 来完成AtomicReference)AtomicBoolean,您可以使用有状态回调对象。它不会改变代码的行为或设计,但可以被认为更干净、更面向 OOP。
class LoadingAction<K, V> {
private boolean called = false;
public V load(final K key) {
called = true;
// load data
return ...;
}
public void executePostLoad() {
if (called) {
// loaded into cache, do X
} else {
// do Y
}
}
}
final class Cache {
private static final ConcurrentHashMap<String, List<String>> CACHE = new ConcurrentHashMap<>();
static List<String> byName(String name) {
final LoadingAction<String, List<String>> loader = new LoadingAction<>();
final List<String> result = CACHE.computeIfAbsent(name, loader::load);
loader.executePostLoad();
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
或者把它翻过来:
class Loader<K, V> {
private boolean called = false;
public V load(final Map<K, V> map, final K key) {
final V result = map.computeIfAbsent(key, this::load);
this.executePostLoad();
return result;
}
private V load(final K key) {
called = true;
// load data
return ...;
}
private void executePostLoad() {
if (called) {
// loaded into cache, do X
} else {
// do Y
}
}
}
final class Cache {
private static final ConcurrentHashMap<String, List<String>> CACHE = new ConcurrentHashMap<>();
static List<String> byName(String name) {
final Loader<String, List<String>> loader = new Loader<>();
return loader.load(CACHE, name);
}
}
Run Code Online (Sandbox Code Playgroud)
构造和加载可以封装在静态方法中:
class Loader<K, V> {
private boolean called = false;
public static <K, V> V load(final Map<K, V> map, final K key) {
final Loader<K, V> loader = new Loader<>();
return loader.doLoad(map, key);
}
private V doLoad(final Map<K, V> map, final K key) {
final V result = map.computeIfAbsent(key, this::load);
this.executePostLoad();
return result;
}
private V load(final K key) {
called = true;
// load data
return ...;
}
private void executePostLoad() {
if (called) {
// loaded into cache, do X
} else {
// do Y
}
}
}
final class Cache {
private static final ConcurrentHashMap<String, List<String>> CACHE = new ConcurrentHashMap<>();
static List<String> byName(String name) {
return Loader.load(CACHE, name);
}
}
Run Code Online (Sandbox Code Playgroud)