2016-03-23 29 views
4

Son zamanlarda tembel nesneleri (ilk erişimi üzerindeki iç durumunu yarattı olacak nesneler) oluşturmak için bir yol tanıtıldı bir makale "Be Lazy With Java 8", okuyun.Klasik tekil

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; 
    } 
} 

Bu model jenerik dışında iyi bilinen tekil desen çok benzer olduğu bulunmuştur:

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(); 
     } 
    } 
} 

Tembel sınıf iç nesne süre erişimi eşitlemek için uçucu elemanı kullanır singleton modelinin birkaç uygulaması vardır (kişisel olarak bir statik final üyesi olan iç yardımcı sınıfıyla kullanmayı tercih ediyorum). Singleton L1 & L2 Önbellektekileri sınıf yükleyici önbelleğe ile bir kez yüklenir ise ikinci desen (Uçucu elemanına), ana bellek bir okuma içeren Tembel nesnesinde getOrCompute yönteme her çağrı yana daha iyi bir performans varsayılmıştır. Ben Intel (R) Core (TM) i5-3470 işlemci @ 3.20GHz ile CentOS 6 benim varsayımını test etmek için JMH kriter kullanılır. kriter benim Git deposundan indirilebilir:

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 

sonuç iki seçenek arasında hiçbir fark, nedenini anlamak değilim olduğunu göstermektedir: Burada

https://github.com/maximkir/LazyObjectVsSingletonPerformance sonuç tablosu vardır. İkinci modelin daha iyi performans göstermesini beklerdim. Herhangi bir fikir? inlining? Derleyici optimizasyonu? Yanlış karşılaştırma testi?

Benchmark kodu:

@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()); 
    } 
+0

Sonuçlar DZone yazı için orijinal kaynağıdır: http://minborgsjavapot.blogspot.com/2016/01/be-lazy- ile-java-8.html – srborlongan

+1

bana öyle görünüyor - sıcak kadar sonra - nihayet sadece (hiç değişmez ve boş değil) uçucu üyesi herhangi birine erişimi veya tutucu sınıfının sabit üyesine karşılaştırın.Yani bu üyelerin başlangıç ​​bölümlerini gerçekten ölçemiyorsunuz (çok sayıda çağrıştan sonra). –

+0

Başlatma, yalnızca bir kez gerçekleştiği için önemli değildir. –

cevap

0

ben eşzamanlılık konusunda uzman değilim, ama senin Tembel başlatıcı yanlış olduğunu görünüyor. Karşılaştırmada, Scope.Thread durumunu kullanırsınız. Ama bu, her iş parçacığının kendi Tembelliğine sahip olacağı anlamına gelir, dolayısıyla gerçek bir eşzamanlılık yoktur.

Lazerli (apache commons'a göre LazyInitializer), Eager ve statik iç sınıfa kendi kriterlerimi yazdım.

istekli paket org.sample;

import java.util.Properties; 

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

    public Properties get(){ 
     return value; 
    } 
} 

Tembel paket 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(); 
    } 
} 

ÖzelliklerSingleton sizinki gibidir.

Deney paket 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(); 
    } 
} 

ileride başvurmak üzere, burada, arada

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