Singleton Pattern은 많은 프로그래밍 언어에서 사용하는 Design Pattern이고,

개인적으로도 가장 자주 활용하는 Pattern 중 하나다.

일반적으로는 아래와 같이 생성자를 private로 선언한 뒤 getInstance 함수내에서

instance가 한번 이상 생성되지 않도록 구현하여 사용했다.

 

만약 Multi Thread 환경에서 동작하게 하려면 getInstance 함수를

Critical Section으로 선언하여 하나 이상의 Thread가 동시에 getInstance() 함수에

접근해서 instance를 생성하는걸 막을 수 있다.

 

지금까지는 위의 함수로 Singleton Pattern을 구현하여 잘 사용하고 있었는데,

실제로 Program이 실행될 때 함수에 Lock을 걸고, Lock을 해제하는 작업이

Multi Thread 환경에서 엄청난 Overhead가 된다고 한다.

 

OS를 배울 때 Critical Section은 가능한 최소한으로 유지하라고 배웠던 기억도 난다.

synchronized block을 함수가 아니라 객체를 생성하는 부분에만 적용해서

객체를 생성할 때만 synchronized block에 접근하도록 수정해보자!

Singleton Pattern에서 객체는 한번만 생성된다는 것을 감안하면 상당한 성능 향상을

기대해볼 수 있을 것 같다.

 

위의 코드가 Multi Thread 환경에서 문제없이 동작해주면 고맙겠지만

Thread 1이 getInstance 함수에 들어와서 instance가 null 인 것까지 확인한 뒤,

Thread2에게 선점되고, Thread2가 getInstance 함수에 들어온다면 문제가 발생한다.

Thread2는 instance가 null이기 때문에 객체를 생성한 뒤 반환할 것이고,

Thread1은 instance가 null 인 것까지 확인을 했기 때문에,  다시 객체를 생성할 것이다. (!!)

 

그럼 synchronized block 내부에서 instance를  다시 확인하면 어떨까?

Singleton Pattern에서 객체는 한번만 생성된다는 점을 생각해보면 위의 코드는

Multi Thread 환경에서도 상당히 빠르게 동작할 것 같고, 문제가 없어 보인다.

 

이론적으로는 위의 double check locking은 문제없이 동작해야 한다.

하지만 자바 플랫폼의 메모리 모델이 ‘난잡한 작성’을 허용하여 double check locking은

완벽한 동작을 보장할 수 없다고 한다.

더 자세한 내용은 이글을 읽어보면 알 수 있다.

 

{ References }

http://www.ibm.com/developerworks/kr/library/j-dcl.html

http://en.wikipedia.org/wiki/Double-checked_locking