加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

使用Java 8 Performance的经典单例与Lazy

发布时间:2020-12-15 02:13:44 所属栏目:Java 来源:网络整理
导读:最近我读了一篇文章“ Be Lazy With Java 8”,它引入了一种创建惰性对象的方法(在第一次访问时将创建其内部状态的对象). public final class LazyT { private volatile T value; public T getOrCompute(SupplierT supplier){ final T result = value; return
最近我读了一篇文章“ 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成员),而Singleton由L1和amp;中缓存的类加载器加载一次. 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和静态内部类.

急于
????package org.sample;

import java.util.Properties;

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

    public Properties get(){
        return value;
    }
}


????package 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和你的一样.

基准
????package 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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读