gpt4 book ai didi

performance - 经典单例 vs. Java 8 性能懒惰

转载 作者:行者123 更新时间:2023-12-01 06:08:03 24 4
gpt4 key购买 nike

最近我读了一篇文章“Be Lazy With Java 8 ”,它介绍了一种创建惰性对象(在第一次访问时创建其内部状态的对象)的方法。

public final class Lazy<T> {

private volatile T value;

public T getOrCompute(Supplier<T> supplier){
final T result = value;
return result == null ? maybeCompute(supplier) : result;
}

private synchronized T maybeCompute(Supplier<T> supplier) {
if (value == null){
value = Objects.requireNonNull(supplier.get());
}
return value;
}
}

我发现这个模式与众所周知的单例模式非常相似,除了泛型:
public class PropertiesSingleton {

public static Properties getProperties(){
return Helper.INSTANCE;
}

private final static class Helper{
private final static Properties INSTANCE = computeWithClassLoaderLock();


private static Properties computeWithClassLoaderLock(){
return new Properties();
}
}
}

Lazy 类使用 volatile 成员来同步对内部对象的访问,而单例模式几乎没有实现(我个人更喜欢将它与具有一个静态最终成员的内部助手类一起使用)。我认为第二种模式具有更好的性能,因为每次调用 Lazy 对象上的 getOrCompute 方法都涉及从主内存读取(由于 volatile 成员),而单例由缓存在 L1 和 L2 内存缓存中的类加载器加载一次。
我使用 JMH 基准测试我对 CentOS 6 和 Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz 的假设。基准测试可以从我的 Git 存储库下载: https://github.com/maximkir/LazyObjectVsSingletonPerformance

以下是结果表:
Benchmark                                   Mode      Cnt   Score   Error  Units
LazyVsSingletonPerformance.testLazy sample 1101716 33.793 ± 0.148 ns/op
LazyVsSingletonPerformance.testSingleton sample 622603 33.993 ± 0.179 ns/op

结果显示这两个选项没有区别,我不明白为什么。我希望第二种模式会表现得更好。有任何想法吗?内联?编译器优化?错误的基准测试?

基准代码:
@State(Scope.Thread)
public class LazyVsSingletonPerformance {

Blackhole bh = new Blackhole();
Lazy<Properties> lazyProperties = new Lazy<>();

public static void main(String... args) throws Exception{
Options opts = new OptionsBuilder()
.include(LazyVsSingletonPerformance.class.getSimpleName())
.warmupIterations(3)
.forks(2)
.measurementIterations(3)
.mode(Mode.SampleTime)
.measurementTime(TimeValue.seconds(10))
.timeUnit(TimeUnit.NANOSECONDS)
.build();

new Runner(opts).run();
}


@Benchmark
public void testLazy(){
bh.consume(lazyProperties.getOrCompute(() -> new Properties()));
}


@Benchmark
public void testSingleton(){
bh.consume(PropertiesSingleton.getProperties());
}

最佳答案

我不是并发方面的专家,但您的 Lazy 初始值设定项似乎不正确。在基准测试中,您使用 Scope.Thread 状态。但这意味着每个线程都会有自己的 Lazy,所以没有真正的并发。

我使用 Lazy(基于 apache commons LazyInitializer )、Eager 和静态内部类编写了自己的基准测试。

渴望的
包 org.sample;

import java.util.Properties;

public class Eager {
private final Properties value = new Properties();

public Properties get(){
return value;
}
}

懒惰的
包 org.sample;
import org.apache.commons.lang3.concurrent.ConcurrentException;
import org.apache.commons.lang3.concurrent.LazyInitializer;

import java.util.Properties;

public class Lazy extends LazyInitializer<Properties> {
@Override
protected Properties initialize() throws ConcurrentException {
return new Properties();
}
}

PropertiesSingleton 是你的。

基准
包 org.sample;
import org.apache.commons.lang3.concurrent.ConcurrentException;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;

import java.util.Properties;

@State(Scope.Benchmark)
public class MyBenchmark {
private Lazy lazyProperties = new Lazy();
private Eager eagerProperties = new Eager();

@Benchmark
public Properties testEager(){
return eagerProperties.get();
}

@Benchmark
public Properties testLazy() throws ConcurrentException {
return lazyProperties.get();
}

@Benchmark
public Properties testSingleton(){
return PropertiesSingleton.getProperties();
}
}

结果
Benchmark                   Mode  Cnt         Score         Error  Units
MyBenchmark.testEager thrpt 20 90980753,160 ± 4075331,777 ops/s
MyBenchmark.testLazy thrpt 20 83876826,598 ± 3445507,139 ops/s
MyBenchmark.testSingleton thrpt 20 82260350,608 ± 3524764,266 ops/s

关于performance - 经典单例 vs. Java 8 性能懒惰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36175421/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com