2010-12-19 17 views
10

Olası Çoğalt:
Efficient way to implement singleton pattern in Javaİş parçacığı güvenli Java'da tekil desen uygulamak için etkili bir yol?

Bu Best Singleton Implementation In Java okuyordu, ama onun iş parçacığı güvenli değil. wiki gereğince

: 1. Çift boş çek:

if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}

Ama Bugs programı bul Bu iki hatalar veriyor. 2. Statik alanın yanlış temsili başlatması.

synchronized (Singleton.class) { 
if (singleton== null) { 
singleton= new Singleton(); 
} 
} 
+1

Bu, yukarıdaki sorunun kopyasıdır; detaylar için bu soruya bakın. Ama bu sorunun bu yararlı bağlantılara sahip olduğundan emin değilim, bu yüzden: [Java'da çift kontrol kilitleme hakkında] (http://www.ibm.com/developerworks/java/library/j-dcl.html) [bunlar] (http://www.ibm.com/developerworks/library/j-jtp02244.html) [iki] (http://www.ibm.com/developerworks/library/j-jtp03304/) Java için güncellemeler 5. Ayrıca [Vikipedi'nin çift kilitlemeli kilitleme hakkındaki makalesine bakın] (http://en.wikipedia.org/wiki/Double-checked_locking). Ancak sorunuza verilen gerçek cevap için, yukarıda bağlantılı soruya bakın. –

cevap

20

en verimli/basit yolu Singleton sadece

enum Singleton { 
    INSTANCE 
} 

bir tembel yükleme yapmak için: en iyi yolu nedir

,

Doğru it mı Not: sınıf yükleme güvenli olduğu için kilitlemeye gerek yoktur. Sınıf varsayılan olarak kesindir ve yapıcı yansıma ile çağrılmaz. INSTANCE veya sınıf kullanılıncaya kadar INSTANCE oluşturulmaz. Eğer endişeleniyorsanız, sınıf yanlışlıkla kullanılabiliyorsa, tekil bir iç sınıfa sarılabilirsin.

final class Singleton { 
    private Singleton() { } 
    static class SingletonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

IMHO, bunun daha iyi bir çözüm olduğunu düşünmek için oldukça paranoyak olmanız gerekir.

+0

İkinci kodunuzda 'enum' kullanmıyorsunuz ama 'class' kullanıyorsunuz, bu yüzden onu nasıl kullanacağımı karıştırıyorum. Ben bir kez bir sınıf başlatmak ve her seferinde bu nesneyi çağırmak için bir enum yapmak istiyorum.Bunu yapabilirim.Geliştirmek için lütfen ayrıntılı bir örnek verin – manish

+0

@Manish Bu durumda, bir "enum" kullanın ilk örnek. –

+0

yah, ama bir sınıfı bir kez nasıl ilklendirebilirim ve 'enum' kullanarak bu örneği her seferinde kullanabilirim. Bu sadece benim en çok neden gördüğüm enton Singleton { INSTANCE } '' dır, fakat çok fazla değil, nesne çağırmak ve başlatmak için değil – manish

2

Efficient way to implement singleton pattern in Javaiçin kabul edilen yanıttaki ilk kod örneği, numaralı ileti dizesidir. INSTANCE'un oluşturulması, sınıf yüklendiğinde sınıf yükleyicisi tarafından gerçekleştirilir; aynen defa gerçekleştirilir, ve bir iş parçacığı güvenli bir şekilde:

public final class Foo { 

    private static final Foo INSTANCE = new Foo(); 

    private Foo() { 
     if (INSTANCE != null) { 
       throw new IllegalStateException("Already instantiated"); 
     } 
    } 

    public static Foo getInstance() { 
     return INSTANCE; 
    } 
} 

(What is an efficient way to implement a singleton pattern in Java? kopyalanan)

söz konusu 2 kod örneği doğru ve evreli, ama her çağrıda senkronizasyonu neden olur Performansı etkileyen getInstance().

+0

Özel kurucuyu korumaz, oldukça paranoyaktır. Yansımayı kullanarak başka bir örnek oluşturmaktan kaçınmayı mı, yoksa kurucuyu arayan iç sınıfları durdurmak mı? –

+0

Bir önceki sorudan bir cevap tartışıyordum, bu yüzden kodu kopyaladım. Şahsen ben de (eğer INSTANCE! = Null) 'kontrol etmeliydim. –

+0

ve bunun için istisna var. ;) –

3

Bu konu hakkında çok şey yazılmıştır. Evet, basit çift kontrol kilitleme deseni güvenli değil. Ancak, statik örneği uçucu olarak bildirerek bunu güvenli hale getirebilirsiniz. Yeni Java Bellek Modeli belirtimi, uçucu ile uğraşırken derleyiciler için bazı kod yeniden sıralama kısıtlamalarını ekler, bu nedenle orijinal riskler ortadan kalkar. örneğini oluştururken

Neyse, nadiren gerçekten bu yüzden genellikle sadece sınıf yükleme sırasında statik oluşturun lazyness bu tür gerekir:

private static MyClass instance = new MyClass(); 

Bu kısa ve net.Eğer gerçekten tembel yapmak istiyorsanız alternatif olarak,, sınıf yükleme özellikleri yararlanmak ve bunu yapabilirsiniz:

public class MyClass { 
    private static class MyClassInit { 
     public static final MyClass instance = new MyClass(); 
    } 

    public static MyClass getInstance() { 
     return MyClassInit.instance; 
    } 
... 
} 

iç içe sınıfı getInstance çağrı ilk saatine kadar yüklenen() edilmeyecektir.

İlgili konular