Skip to main content

☕ Java Singleton Tasarım Deseni: En İyi Uygulamalar ve Örneklerle Rehber


🎯 Bu Rehberde Ne Öğreneceksiniz?

Bu rehber, Java’nın Creational (Yaratımsal) Tasarım Desenleri arasında yer alan Singleton desenini derinlemesine anlatır.
Bir sınıfın yalnızca tek bir örneğinin oluşturulmasını sağlayan bu deseni, farklı yaklaşımlar ve güvenli uygulama yöntemleriyle öğreneceksiniz.


🧠 Teknik Özet

Amaç: Uygulama boyunca yalnızca bir örnek (instance) oluşturmak ve bu örneğe global erişim sağlamak.
Kullanım alanı: Loglama, veritabanı bağlantısı, önbellekleme, thread pool yönetimi.
Öğrenecekleriniz:

  • Singleton prensipleri
  • Eager, Static Block, Lazy ve Thread-Safe yaklaşımlar
  • Bill Pugh yöntemi (önerilen çözüm)
  • Reflection ve Serialization riskleri ve koruma yolları

🧩 Singleton Temel Prensipleri

Bir sınıfın Singleton olabilmesi için:

  1. Private kurucu → yeni nesne oluşturmayı engeller.
  2. Private static örnek → tek instance’ı saklar.
  3. Public static erişim metodu → dış dünyaya bu örneği döndürür.

⚙️ 1. Erken Başlatma (Eager Initialization)

Sınıf yüklenirken örnek oluşturulur.

public class EagerInitializedSingleton {
private static final EagerInitializedSingleton ornek = new EagerInitializedSingleton();
private EagerInitializedSingleton(){}
public static EagerInitializedSingleton getInstance() { return ornek; }
}

➡️ Basit ama kullanılmasa bile bellekte yer kaplar.


⚙️ 2. Statik Blok Başlatma (Static Block Initialization)

Erken başlatma ile benzerdir, fakat hata yönetimi sağlar.


public class StaticBlockSingleton {
private static StaticBlockSingleton ornek;
private StaticBlockSingleton(){}
static {
try { ornek = new StaticBlockSingleton(); }
catch (Exception e) { throw new RuntimeException("Singleton hatası"); }
}
public static StaticBlockSingleton getInstance() { return ornek; }
}

➡️ Exception handling avantajı sunar, ancak hâlâ erken yükleme yapar.


⚙️ 3. Tembel Başlatma (Lazy Initialization)

Örnek yalnızca ihtiyaç duyulduğunda oluşturulur.


public class LazyInitializedSingleton {
private static LazyInitializedSingleton ornek;
private LazyInitializedSingleton(){}
public static LazyInitializedSingleton getInstance() {
if (ornek == null) ornek = new LazyInitializedSingleton();
return ornek;
}
}

➡️ Kaynak dostu ama çoklu thread ortamında güvenli değildir.


⚙️ 4. Thread-Safe Singleton

Senkronizasyon ile çoklu iş parçacığında güvenlik sağlar.


public static synchronized ThreadSafeSingleton getInstance() {
if (ornek == null) ornek = new ThreadSafeSingleton();
return ornek;
}

➡️ Thread-safe ama performans maliyeti yüksektir.

🔄 Double-Checked Locking

Sadece ilk oluşturma sırasında senkronize eder.


if (ornek == null) {
synchronized (ThreadSafeSingleton.class) {
if (ornek == null) ornek = new ThreadSafeSingleton();
}
}

➡️ Performans ve güvenliği dengeler.


⚙️ 5. Bill Pugh Singleton (En Güvenli Yöntem)

Java 5 sonrası en verimli ve güvenli yöntemdir.


public class BillPughSingleton {
private BillPughSingleton(){}
private static class Yardimci {
private static final BillPughSingleton ORNEK = new BillPughSingleton();
}
public static BillPughSingleton getInstance() { return Yardimci.ORNEK; }
}

➡️ Senkronizasyonsuz thread-safe ve lazy yükleme sağlar.


⚠️ 6. Reflection ile Singleton’ın Bozulması

Reflection özel kurucuya erişip yeni nesne yaratabilir. Bunu engellemek için kurucuya şu kontrol eklenebilir:


private Singleton() {
if (instance != null) throw new RuntimeException("Yalnızca bir örnek oluşturulabilir!");
}

➡️ Reflection saldırısına karşı koruma sağlar.


🟣 7. Enum Singleton

Joshua Bloch’un önerdiği en güvenli çözüm:


public enum EnumSingleton {
ORNEK;
public void islemYap() { /* ... */ }
}

➡️ Reflection’a karşı bağışıktır, JVM yalnızca bir örnek üretir.


🧱 8. Serileştirme (Serialization) ve readResolve()

Serialization yeni nesne oluşturabilir. Bunu engellemek için:


protected Object readResolve() { return getInstance(); }

➡️ Ters serileştirme sonrası aynı instance korunur.


💬 Sıkça Sorulan Sorular (SSS)

  1. Singleton ve statik sınıf farkı nedir?

Singleton bir nesnedir, statik sınıf değildir; durum (state) tutabilir.

  1. Bill Pugh neden en iyi yöntemdir?

Thread-safe, lazy ve senkronizasyon yükü yoktur.

  1. readResolve() neden gereklidir?

Deserileştirme sırasında yeni nesne oluşmasını engeller.

  1. Singleton nerede kullanılmaz?

Çoklu bağımlılıklı (state-sharing) yapılarda test edilebilirliği düşürür.

  1. Enum Singleton neden tercih edilir?

Hem Reflection hem Serialization’a karşı doğal koruma sağlar.


✅ Sonuç

Bu rehberde, Java Singleton tasarım desenini farklı uygulama yöntemleriyle öğrendiniz. Artık hangi yaklaşımın performans, güvenlik ve esneklik açısından uygun olduğunu biliyorsunuz.

🚀 Rabisu Bulut üzerinde kendi Java projenizi başlatın ve bu desenleri gerçek bir ortamda test edin.