文書の過去の版を表示しています。
the Definition of Singleton Pattern
싱글턴 패턴은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴입니다.
특별히 대단한 내용은 없지만, 하나씩 짚고 넘어가보도록 하겠습니다.
- 실제로 어떤 식으로 싱글턴 패턴을 적용할까요? 클래스에서 자신의 단 하나뿐인 인스턴스를 관리하도록 만들면 됩니다.
그리고 다른 어떤 클래스에서도 자신의 인스턴스를 추가로 만들지 못하도록 해야 합니다. 인스턴스가 필요하면 반드시 클래스
자신을 거치도록 해야 되겠죠.
- 그리고 어디서든 그 인스턴스에 접근할 수 있도록 만들어야 합니다. 다른 객체에서 이 인스턴스가 필요하면 언제든지
클래스한테 요청을 할 수 있게 만들고, 요청이 들어오면 그 하나뿐인 인스턴스를 건네주도록 만들어야 하죠. 싱글턴이
'게으르게' 생성되도록 구현할 수도 있습니다. 그 클래스의 객체가 자원을 많이 잡아먹는 경우에는 이런 게으른 생성
기법이 꽤 유용하죠.
implementation 1
고전적인 싱글턴 구현법을 소개합니다.
public class Singleton{ private static Singleton uniqueInstance; private Singleton(){} public static Singleton getInstance(){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } }
생성자를 private으로 선언함으로써 다른 클래스에서 instance를 함부로 생성하지 못하게 합니다.
언뜻 보기에는 그럴듯 해 보이죠. 하지만 이 구현법에는 몇가지 문제점이 있습니다.
무엇이 문제일까요?
스레드가 하나라면 이 코드는 잘 작동할 것입니다. 스레드가 하나 더 추가되면 어떤 일이 벌어질까요?
운 나쁘게 uniqueInstance가 null임을 확인하고 instance를 생성하려는 사이 다른
스레드에서
instance를 만들어버리게 되는 상황이 발생할 수도 있습니다.
a issue of multi-thread problem
getInstance()를 동기화시키기만 하면 멀티스레딩과 관련된 문제가 간단하게 해결됩니다.
다음의 코드를 살펴보세요.
public class Singleton{ private static Singleton uniqueInstance; private Singleton(){} public static synchronized Singleton getInstance(){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } }
이렇게 하면 문제가 해결되겠지만, 동기화를 하면 속도 문제가 생기지 않을까요?
좋은 지적입니다. 그리고 조금 더 생각해 보면 동기화를 하기가 정말 아깝다는 느낌이 들 수도 있습니다.
사실 동기화가 꼭 필요한 시점은 이 메소드가 시작되는 때 뿐입니다. 바꿔 말하자면, 일단 uniqueInstance
변수에 Singleton 인스턴스를 대입하고 나면 굳이 이 메소드를 동기화된 상태로 유지시킬 필요가 없다는 거죠.
첫 번째 과정을 제외하면 동기화는 불필요한 오버헤드만 증가시킬 뿐입니다.
Alternative
더 효율적인 방법은 없을까요?
대부분의 자바 애플리케이션에서 싱글턴이 다중 스레드 환경에서 돌아갈 수도 있도록 만들어야 합니다.
하지만 getInstance()메소드를 동기화시키려면 적지 않은 대가를 치뤄야 합니다. 혹시 다른 방법은 없을까요?
몇가지 방법을 생각해 볼 수 있을 겁니다.
1.getInstance()의 속도가 그리 중요하지 않다면 그냥 둡니다.
그래도 됩니다. getInstance()메소드가 애플리케이션에 큰 부담을 주지 않는다면 그냥 놔눠도 됩니다.
getInstance()를 동기화시키는 게 그리 어려운 일도 아니고, 효율 면에서도 괜찮을 수 있습니다.
메소드를 동기화하면 성능이 100배정도 저하된다는 것은 기억해 둡시다. 만약 getInstance()가 애
플리케이션에서 병목으로 작용한다면 다른 방법을 생각해봐야 합니다.
2.인스턴스를 필요할 때 생성하지 말고, 처음부터 만들어 버립니다.