Design Patterns – 01 – Singleton Design Pattern

Acknowledgement/Takdim

— Verin. Benim istediğim size yaramaz. Ne yapacaksınız onu ? Kaç seneden beri Cürcan’da yazmakla uğraşıyordum. Ne kadar emek verdim onlara ders notlarım benim.

— Sen ilim öğrendim, şu kadar göz nuru döktüm diyorsun halbuki biz senin o kadar emeğini ve bu kadar bilgini bir anda elinden aldık şimdi ne gelir elinden, bu kadar çalışmanın ne değeri var?

Bundan sonra sadece yazarak değil kavrayarak öğreneceğine, mürekkep adamı değil kafa adamı olacağına,satırlara değil gönüllere yerletirmeye çalışacağına söz vermişti Gazali.
Ve bu artık geleceğin Hüccet’ül İslâmı için bir prensip halini alacaktı.

…subhâneke lâ ilme lenâ illâ mâ allemtenâ inneke entel alîmul hakîm
Bakara,32

Prerequisite/On Kosul

Design Pattern konularini iyi anlayabilmek icin iyi seviyede Object Oriented dil bilgisi ve yaklasimi gereklidir.
Bu konuda problem varsa oncelikle temel Java SE bilgisi ve Object Oriented dusunme prensibini halletmek gereklidir.

Hello Design Pattern

Design Pattern’lar ; belirli tasarim/design problemlerini cozmek icin kullanilan , kanitlanmis soyut (abstract) ve tekrar kullanilabilen (reusable) yaklasimlardir.
Karsilastigimiz bir design/tasarim problemine/ihtiyacina karsilik bir Design Pattern yaklasimi olacaktir.
Burada orneklerimizi tabi Java ile programlayacagiz bununla birlikte Design Pattern kavrami programlama dilinden bagimsizdir.
Object Oriented yaklasimin amaclarindan birtanesi de reusable code’tur.
Design Pattern’lari dogru ve verimli sekilde kullanmak “reusable code” prensibini bir ust level’e tasiyacaktir.

Design Pattern denilince akla Gang of Four gelecektir.
https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

Design Patter’ler genel olarak 3 kategoriye ayrilirlar ;

  • Creational Design Patterns
  • Structural Design Patterns
  • Behavioral Design Patterns

Ilk olarak Creational Design Pattern’lari incelemeyec baslayacagiz.

Creational Design Pattern’lar

  • Singleton Pattern
  • Factory Method Pattern
  • Abstract Factory Pattern
  • Builder Pattern
  • Prototype Pattern

Singleton Design Pattern

Gang of Four’da Singleton Design Pattern icin su tanim yer almaktadir.
Ensure a class has only one instance, and provide a global point of access to it.

Singleton Design Pattern’i , ilgili siniftan sadece tek bir obje/instance olusmasini garanti eder.

Singleton Design Pattern’in genel olarak ozellikleri ;

  • private constructor
    Boylece baska sinif bu sinifin bir objesini/instance olusturamaz.
  • global access point/public static method
    Ilgili objeye ulasmak icin ; global access/genel erisim noktasi
    Bu metod diger siniflar tarafindan ulasilan nokta olacaktir.
  • private static variable
    Ilgili sinif tipinde private static variable

Ornek olarak java.lang.Runtime da Singleton Design Pattern kullanilmaktadir.

public class Runtime {
    
    private static Runtime currentRuntime = new Runtime();

        public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

    ...

}

Singleton Design Patter’ icin cesitli yaklasimlar yer almaktadir.

  • Eager Initialization
  • Static Block Initialization
  • Lazy Initialization
  • Thread Safe Singleton
  • Double Checked Locking
  • Bill Pugh Singleton
  • Joshua Bloch Singleton

Eager Initialization

Eager , kelime anlami olarak ; istekli , sabirsiz , canli gibi anlamlara gelmektedir.
Fakat bu kelimeler tam olarak anlatmak istedigimizi karsilamaktadir.

Eager Initialization yaklasiminda Singleton objemiz , class loading zamaninda olusturulur.
Singleton obje henuz ihtiyac olmadigi zaman ,sistem baslarken/ayaga kalkarken (boostrap) olusturulur. Eger Singleton objemiz expensive/maliyetli ise bu durumda sistemin baslangicini yavaslatacaktir.

EagerInitialization.java

package _01._01.singleton.eager.initialization;

public class EagerInitialization {

	private static final EagerInitialization instance = new EagerInitialization();

	private EagerInitialization() {

	}

	public static EagerInitialization getInstance() {
		return instance;
	}
}
  • Kodu inceleyecek olursak private constructor kullandik.
  • private static EagerInitialization tipinde bir variable tanimladik.
  • public static getInstance metodu geriye EagerInitialization tipinde objeyi donmektedir.

EagerInitializationTest.java

package _01._01.singleton.eager.initialization;

public class EagerInitializationTest {

	public static void main(String[] args) {
		
		EagerInitialization instance1 = EagerInitialization.getInstance();
		EagerInitialization instance2 = EagerInitialization.getInstance();

		System.out.println(instance1 == instance2);
	}
}

Ornegimizi calistirdigimizda ;

true

Static Block Initialization

Static Block Initialization yaklasimi Eager Initialization yaklasimina benzer.
Arti yon olarak exception handling mekanizmasini kullanabiliriz.
Bu yaklasim da Eager yaklasimdir.

Initialize Block hakkinda detayli bilgi icin ;
http://www.injavawetrust.com/pure-java-32-initialization-blocks/

StaticBlockInitialization.java

package _01._02.singleton.staticblock.initialization;

public class StaticBlockInitialization {

	private StaticBlockInitialization() {
		
	}

	private static StaticBlockInitialization instance;

	static {
		try {
			instance = new StaticBlockInitialization();
		} catch (Exception e) {
			// handle exception
		}
	}

	public static StaticBlockInitialization getInstance() {
		return instance;
	}
}

Lazy Initialization

Lazy Initialization yaklasiminda Eager yaklasimindan farkli olarak Singleton objemiz ilk defa kullanilacagi zaman olusturulacaktir , yani ilk defa getInstance metodu cagrildiginda obje olusacaktir.

LazyInitialization.java

package _01._03.singleton.lazy.initialization;

public class LazyInitialization {

	private static LazyInitialization instance;

	private LazyInitialization() {
		
	}

	//Not Thread Safe!
	public static LazyInitialization getInstance() {
		if (instance == null) {
			instance = new LazyInitialization();
		}
		return instance;
	}
}

Multi thread yaklasim icin burada Not Thread Safe durumu ortaya cikacaktir.

ThreadA ve ThreadB olmak uzere 2 tane thread olsun ;
getInstance metodunu bu 2 thread cagirsin.

  • ThreadA calisir;
    instance==null satiri calisir ; sart saglandigi icin bir alt satira gecer
    Bu noktada ThreadA durabilir.
  • ThreadB calisir;
    instance==null satiri calisir; instance henuz null oldugu icin sart saglanir.
    Bir alt satira gecer LazyInitialization objesi olusur.
  • Sonrasinda ThreadA calismaya devam eder.
    LazyInitialization objesi olusur.

Singleton Design Pattern yaklasimi her zaman tek bir obje olusma prensibine dayanir.
Burada 2 tane obje olusma riski yer almaktadir.

Thread Safe Singleton

ThreadSafeSingleton.java

package _01._04.singleton.threadsafe;

public class ThreadSafeSingleton {

	private static ThreadSafeSingleton instance;

	private ThreadSafeSingleton() {

	}

	// Thread Safe
	public static synchronized ThreadSafeSingleton getInstance() {
		if (instance == null) {
			instance = new ThreadSafeSingleton();
		}
		return instance;
	}
}

static synchronized metodumuza ayni anda sadece tek bir Thread ulasabilir. Dolayisiyla burada Thread Safe ozelligini saglayabiliriz.

synchronized metotlar , unsynchronized metotlara gore cok yavas calismaktadir. Performans iyilestirmesi olarak sadece obje/instance olusturdugumuz kismi synchronized block arasina alalim.

//Not we have multiple thread issue !
//Simdi birden fazla thread icin problem ortaya cikabilir.
public static ThreadSafeSingleton getInstance() {
	if (instance == null) {
		synchronized(ThreadSafeSingleton.class){
			instance = new ThreadSafeSingleton();
		}
	}
	return instance;
}
  • ThreadA synchronized block’a girer.
    assignment/atama islemini yapmadan durur (preempted)
  • Sonrasinda ThreadB instace null oldugu icin if bloguna girer.
  • ThreadA assignment/atama islemini gerceklestirir.
  • Sonrasinda ThreadB synchronized block’a girer ve yeni bir obje/instance olusur , atama/assignment islemini gerceklestirir.

Singleton yaklasiminda tek bir obje olusmasi gerekirken burada 2 farkli obje olustu.
Peki bu problemi cozebilir miyiz ? Devam edelim …

Double Checked Locking

Double Checked Locking mekanizmasi yukarida bahsettigimiz probleme karsi cozum saglamaktadir.
Double Checked Locking mekanizmasinda 2 tane null kontrolu yapariz.

DoubleCheckedLocking.java

package _01._05.singleton.doublechecked;

public class DoubleCheckedLocking {

	// The volatile keyword ensures that multiple threads handle "instance"
	// variable correctly when it is being initialized to the
	// SingletonDoubleCheckedLocking

	// Double Checked Locking is fixed in Java 1.5
	// http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
	private volatile static DoubleCheckedLocking instance;

	private DoubleCheckedLocking() {

	}

	public static DoubleCheckedLocking getInstance() {
		if (instance == null) {
			synchronized (DoubleCheckedLocking.class) {
				if (instance == null) {
					instance = new DoubleCheckedLocking();
				}
			}
		}
		return instance;
	}
}

Double Checked Locking mekanizmasi Java 1.5’e kadar problem teskil ediyordu.

http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking–clever–but-broken.html

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

http://stackoverflow.com/questions/7855700/why-is-volatile-used-in-this-example-of-double-checked-locking

volatile keyword’u , visibility problem’ina karsi cozum sunmaktadir.
http://www.injavawetrust.com/pure-java-90-thread-07-atomic-volatile/

Bill Pugh Singleton

Bill Pugh Singleton yaklasiminda static nested class kullanilir.
Bu yaklasim en cok onerilen Singleton yaklasimidir.

static nested class hakkinda bilgi icin ;
http://www.injavawetrust.com/pure-java-83-nested-class-static-nested-class/

BillPughSingleton.java

Bill Pugh tekniginde static nested class icerisinde Outer sinifin objesini olusturuyoruz. Bu yaklasim Lazy Initialization’dir ve Thread Safe tir.
Bu yaklasim/teknik “Initialization-on-demand holder” olarak isimlendirilir.
https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom

package _01._06.singleton.billpugh;

public class BillPughSingleton {

	private BillPughSingleton() {

	}

	private static class SingletonHelper {
		private static final BillPughSingleton INSTANCE = new BillPughSingleton();
	}

	//Thread Safe
	public static BillPughSingleton getInstance() {
		return SingletonHelper.INSTANCE;
	}
}

Joshua Bloch Singleton

Bir baska yaklasim olarak , Joshua Bloch , Effective Java kitabinda Enum yaklasiminin kullanilmasini onermektedir.

JoshuaBlochSingleton.java

package _01._08.singleton.joshuabloch;

public enum JoshuaBlochSingleton {
	INSTANCE;
	// a single-element enum type is the best way to implement a singleton
	// Effective Java , Item 3
	// Joshua Bloch
}

Singleton and Serialization

Serialization(Serilestirme) , “bu objeyi instance variable’lariyla birlikte kaydet(save)” anlamina gelmektedir.
Bu durumda ilgili sinifin Serializable olmasi gereklidir yani Serializable arabimini implements etmelidir.

Daha fazla bilgi icin ;
http://www.injavawetrust.com/pure-java-60-file-and-io-05-serialization/

package java.io;
public interface Serializable {
}

SerializedSingleton.java

package _01._08.singleton.serializable;

import java.io.Serializable;

public class SerializedSingleton implements Serializable {

	private static final long serialVersionUID = 1L;

	private SerializedSingleton() {
	}

	private static class SingletonHelper {
		private static final SerializedSingleton INSTANCE = new SerializedSingleton();
	}

	public static SerializedSingleton getInstance() {
		return SingletonHelper.INSTANCE;
	}


}

SerializedSingletonTest.java

package _01._08.singleton.serializable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializedSingletonTest {
	public static void main(String[] args) throws IOException, ClassNotFoundException {

		SerializedSingleton instance = SerializedSingleton.getInstance();

		FileOutputStream fileOutputStream = new FileOutputStream("singleton.serial");
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
		objectOutputStream.writeObject(instance);
		objectOutputStream.flush();
		objectOutputStream.close();

		FileInputStream fileInputStream = new FileInputStream("singleton.serial");
		ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);

		SerializedSingleton deserialized = (SerializedSingleton) objectInputStream.readObject();
		objectInputStream.close();

		System.out.println(instance == deserialized);

	}
}


Ornegimizi calistirdigimizda ;

false

readResolve metodunu uyguladigimizda problem cozulecektir ;

	private Object readResolve() {
		System.out.println("readResolve is called...");
		return getInstance();
	}

Ornegimizi tekrar calistirdigimizda ;

readResolve is called...
true

Github kaynak kodlar / source folder
leventerguder/injavawetrust.designpattern

Yazimi burada sonlandiriyorum.
Herkese bol Javali gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *