差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
| study:java:design_pattern:singleton [2008/08/14 13:22] – banana | study:java:design_pattern:singleton [2014/01/09 00:12] (現在) – banana | ||
|---|---|---|---|
| 行 17: | 行 17: | ||
| 기법이 꽤 유용하죠. | 기법이 꽤 유용하죠. | ||
| - | ===== implementation | + | {{keywords> |
| + | |||
| + | ===== Implementation | ||
| 고전적인 싱글턴 구현법을 소개합니다. | 고전적인 싱글턴 구현법을 소개합니다. | ||
| <code java> | <code java> | ||
| - | public class Singleton{ | + | public class Singleton { |
| | | ||
| - | | + | |
| - | | + | |
| - | | + | if (uniqueInstance == null) { |
| uniqueInstance = new Singleton(); | uniqueInstance = new Singleton(); | ||
| } | } | ||
| 行 42: | 行 44: | ||
| - | ===== a issue of multi-thread problem ===== | + | |
| + | ===== Multi-thread problem ===== | ||
| getInstance()를 동기화시키기만 하면 멀티스레딩과 관련된 문제가 간단하게 해결됩니다.\\ | getInstance()를 동기화시키기만 하면 멀티스레딩과 관련된 문제가 간단하게 해결됩니다.\\ | ||
| 다음의 코드를 살펴보세요. | 다음의 코드를 살펴보세요. | ||
| <code java> | <code java> | ||
| - | public class Singleton{ | + | public class Singleton { |
| | | ||
| - | | + | |
| - | | + | |
| - | | + | if (uniqueInstance == null) { |
| | | ||
| } | } | ||
| 行 64: | 行 67: | ||
| 변수에 Singleton 인스턴스를 대입하고 나면 굳이 이 메소드를 동기화된 상태로 유지시킬 필요가 없다는 거죠.\\ | 변수에 Singleton 인스턴스를 대입하고 나면 굳이 이 메소드를 동기화된 상태로 유지시킬 필요가 없다는 거죠.\\ | ||
| 첫 번째 과정을 제외하면 동기화는 불필요한 오버헤드만 증가시킬 뿐입니다. | 첫 번째 과정을 제외하면 동기화는 불필요한 오버헤드만 증가시킬 뿐입니다. | ||
| + | |||
| ===== Alternative ===== | ===== Alternative ===== | ||
| 行 80: | 行 84: | ||
| **2.인스턴스를 필요할 때 생성하지 말고, 처음부터 만들어 버립니다.**\\ | **2.인스턴스를 필요할 때 생성하지 말고, 처음부터 만들어 버립니다.**\\ | ||
| + | 애플리케이션에서 반드시 Singleton의 인스턴스를 생성하고, | ||
| + | 인스턴스를 실행중에 수시로 만들고 관리하기가 성가시다면 다음과 같은 식으로 처음부터 Singleton\\ | ||
| + | 인스턴스를 만들어버리는 것도 괜찮은 방법입니다. | ||
| + | |||
| + | <code java> | ||
| + | public class Singleton { | ||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 이런 접근법을 사용하면 클래스가 로딩될 때 JVM에서 Singleton의 유일한 인스턴스를 생성해 줍니다.\\ | ||
| + | JVM에서 유일한 인스턴스를 생성하기 전에는 그 어떤 스레드도 uniqueInstance를 정적변수에 접근할 수\\ | ||
| + | 없습니다. | ||
| + | |||
| + | **3." | ||
| + | DCL(Double-Checking Locking)을 사용하면, | ||
| + | 있지 않았을 때만 동기화를 할 수 있습니다. 이렇게 하면 처음에만 동기화를 하고 나중에는 동기화를 하지\\ | ||
| + | 않아도 됩니다. 바로 우리가 원하던 거죠. | ||
| + | |||
| + | <code java> | ||
| + | public class Singleton { | ||
| + | private volatile static Singleton uniqueInstance; | ||
| + | |||
| + | private Singleton() {} | ||
| + | |||
| + | public static Singleton getInstance() { | ||
| + | if (uniqueInstance == null) { | ||
| + | synchronized(Singleton.class) { | ||
| + | if (uniqueInstance == null) { | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | return uniqueInstance; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 인스턴스를 생성하기에 앞서 인스턴스가 있는지 확인하고, | ||
| + | 이렇게 하면 처음에만 동기화가 되겠죠. 블럭으로 들어온 후에도 다시 한 번 변수가 null인지 확인\\ | ||
| + | 한 다음 인스턴스를 생성합니다. **volatile**키워드를 사용하면 멀티스레딩을 쓰더라도 uniqueInstance\\ | ||
| + | 변수가 Singleton인스턴스로 초기화되는 과정이 올바르게 진행되도록 할 수 있습니다.\\ | ||
| + | |||
| + | 하지만 DCL을 이용할 경우 몇가지 주의할 점이 있습니다.\\ | ||
| + | - DCL을 사용하는 방법은 자바2 버전 5(자바 1.5)보다 전에 나온 버전에서는 쓸 수 없습니다.(volatile) | ||
| + | - 클래스 로더가 여러개 있으면 싱글턴이 제대로 작동하지 않고, 여러개의 인스턴스가 생길 수 있습니다. | ||
| + | - 1.2버전보다 전에 나온 JVM을 사용하는 경우에는 가비지 컬렉터 관련 버그((자바 1.2가 나오기 전까지는 가비지 컬렉터의 버그 때문에 싱글턴에 대한 전역 레퍼런스가 없는 경우에 아직 다 쓰지도 않는 싱글턴이 가비지 컬렉터에 의해 제거되는 일이 있었습니다. 즉, 싱글턴을 만들 수는 있지만 그 싱글턴에 대한 유일한 레퍼런스가 싱글턴 자체에만 있는 경우에는 가비지 컬렉터에 의해 그 인스턴스가 제거될 수도 있었죠. 싱글턴이 제거되고 나면 getInstance()를 호출했을 때 갓 만들어진 새 싱글턴이 리턴되기 때문에 아주 골치아픈 버그가 생길 수 있었습니다. 조금 전까지 잘 쓰고 있었는데, | ||
| + | |||
| + | |||