Java8是否对供应商提供缓存支持?
guava库有自己的库,它不扩展Java8。此外,番石榴还为供应商提供了缓存Java8是否对供应商提供缓存支持?,java,java-8,guava,Java,Java 8,Guava,guava库有自己的库,它不扩展Java8。此外,番石榴还为供应商提供了缓存 除了Java 8供应商之外,还有类似的功能吗?没有用于记忆的内置Java函数,尽管实现它并不困难,例如: public static <T> Supplier<T> memoize(Supplier<T> delegate) { AtomicReference<T> value = new AtomicReference<>(); return
除了Java 8供应商之外,还有类似的功能吗?没有用于记忆的内置Java函数,尽管实现它并不困难,例如:
public static <T> Supplier<T> memoize(Supplier<T> delegate) {
AtomicReference<T> value = new AtomicReference<>();
return () -> {
T val = value.get();
if (val == null) {
val = value.updateAndGet(cur -> cur == null ?
Objects.requireNonNull(delegate.get()) : cur);
}
return val;
};
}
公共静态供应商备忘录(供应商代表){
AtomicReference值=新的AtomicReference();
返回()->{
T val=value.get();
if(val==null){
val=value.updateAndGet(cur->cur==null?
Objects.requirennull(delegate.get()):cur);
}
返回val;
};
}
请注意,存在不同的实现方法。如果记忆供应商同时多次从不同线程请求,则上述实现可能多次调用委托。有时,这种实现优于使用锁的显式同步。如果首选锁定,则可以使用DCL:
public static <T> Supplier<T> memoizeLock(Supplier<T> delegate) {
AtomicReference<T> value = new AtomicReference<>();
return () -> {
T val = value.get();
if (val == null) {
synchronized(value) {
val = value.get();
if (val == null) {
val = Objects.requireNonNull(delegate.get());
value.set(val);
}
}
}
return val;
};
}
公共静态供应商备忘录(供应商代表){
AtomicReference值=新的AtomicReference();
返回()->{
T val=value.get();
if(val==null){
已同步(值){
val=value.get();
if(val==null){
val=Objects.requirennull(delegate.get());
值集(val);
}
}
}
返回val;
};
}
另外请注意,正如@LouisWasserman在评论中正确提到的,您可以使用方法引用轻松地将JDK供应商转换为Guava供应商,反之亦然:
java.util.function.Supplier<String> jdkSupplier = () -> "test";
com.google.common.base.Supplier<String> guavaSupplier = jdkSupplier::get;
java.util.function.Supplier<String> jdkSupplierBack = guavaSupplier::get;
java.util.function.Supplier jdkSupplier=()->“测试”;
com.google.common.base.Supplier guavaSupplier=jdkSupplier::get;
java.util.function.Supplier jdkSupplierBack=guavaSupplier::get;
因此,在Guava和JDK函数之间切换不是什么大问题。最简单的解决方案是
public static <T> Supplier<T> memoize(Supplier<T> original) {
ConcurrentHashMap<Object, T> store=new ConcurrentHashMap<>();
return ()->store.computeIfAbsent("dummy", key->original.get());
}
公共静态供应商备忘录(供应商原件){
ConcurrentHashMap存储=新建ConcurrentHashMap();
return()->store.computeFabSent(“dummy”,key->original.get());
}
然而,最简单的并不总是最有效的
如果您想要一个干净高效的解决方案,求助于匿名内部类来保持可变状态将获得回报:
public static <T> Supplier<T> memoize1(Supplier<T> original) {
return new Supplier<T>() {
Supplier<T> delegate = this::firstTime;
boolean initialized;
public T get() {
return delegate.get();
}
private synchronized T firstTime() {
if(!initialized) {
T value=original.get();
delegate=() -> value;
initialized=true;
}
return delegate.get();
}
};
}
公共静态供应商备忘录1(供应商原件){
退回新供应商(){
供应商代表=此::首次;
布尔初始化;
公共部门得不到{
返回delegate.get();
}
private synchronized T firstTime(){
如果(!已初始化){
T value=original.get();
委托=()->值;
初始化=真;
}
返回delegate.get();
}
};
}
这将使用一个代理供应商,该供应商将执行第一次操作,然后将自己替换为一个无条件返回第一次评估捕获结果的供应商。由于它具有final
字段语义,因此可以无条件地返回它,而无需任何额外的同步
在
synchronized
方法firstTime()
中,仍然需要一个initialized
标志,因为如果在初始化过程中并发访问,在替换委托之前,多个线程可能会在方法的条目处等待。因此,这些线程需要检测到初始化已经完成。所有后续访问都将读取新的代理供应商并快速获取值。Java 8上Guava 20的简单包装:
static <T> java.util.function.Supplier<T> memoize(java.util.function.Supplier<? extends T> supplier) {
return com.google.common.base.Suppliers.memoize(supplier::get)::get;
}
静态java.util.function.Supplier memoize(java.util.function.Supplier不完全正确,但您只需在末尾编写::get
即可轻松在j.u.f.Suppliers和c.g.c.b.Suppliers之间转换。正如@LouisWasserman所建议的,您可以通过基本上执行“return Suppliers.memoize”来为番石榴Suppliers制作包装器::memoize(委托::获取)::获取很遗憾Suppliers.memoize没有进入jdk8标准库,因为它对我来说似乎是一个非常低风险的添加。在这种情况下,你真的不需要AtomicReference
,是吗?它似乎被用作lambda可以关闭的可变容器。如果你想保存一个对象我想你可以返回一个带有volatile值
字段的匿名类实例。在this
@Lii,原子引用
上的同步只是一个带有单个字段的对象,它提供了此处所需的volatile读/写语义。可以用匿名类volatile字段替换它(仅在第二个示例中,而不是在第一个示例中),但这类优化是否重要并不十分明显。此外,锁定公共可用对象被认为是一种不好的做法。您可以通过记住表单的另一个供应商()->val
。这样,您就可以使用捕获值的final
字段语义。@glts:委托.get()
将在第一次调用的synchronized
方法firstTime()
或与()->value
lambda表达式,而value
实际上是final。访问该捕获的值相当于读取一个final
字段,该字段无需额外同步,是安全的。如果线程看到委托
引用的过时值,它将通过已同步
firstTime()
方法进行一次调用,并在调用后知道最新的值,因此所有后续调用都会快速进行。在这种情况下,委托
为什么不需要标记为易失性
?@Mark Elliot:捕获的局部变量值具有最终
字段seman