Writing /volume1/Web/Public/dokuwiki/data/log/deprecated/2024-11-15.log failed

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
study:java:design_pattern:singleton [2008/08/14 12:49] bananastudy:java:design_pattern:singleton [2014/01/09 00:12] (現在) banana
行 16: 行 16:
  '게으르게' 생성되도록 구현할 수도 있습니다. 그 클래스의 객체가 자원을 많이 잡아먹는 경우에는 이런 게으른 생성\\  '게으르게' 생성되도록 구현할 수도 있습니다. 그 클래스의 객체가 자원을 많이 잡아먹는 경우에는 이런 게으른 생성\\
 기법이 꽤 유용하죠. 기법이 꽤 유용하죠.
 +
 +{{keywords>Singleton Pattern}}
 +
 +===== Implementation 1 =====
 +고전적인 싱글턴 구현법을 소개합니다.
 +<code java>
 +public class Singleton {
 +     private static Singleton uniqueInstance;
 +
 +     private Singleton() {}
 +
 +     public static Singleton getInstance() {
 +         if (uniqueInstance == null) {
 +              uniqueInstance = new Singleton();
 +         }
 +         return uniqueInstance;
 +     }
 +}
 +</code>
 +생성자를 private으로 선언함으로써 다른 클래스에서 instance를 함부로 생성하지 못하게 합니다.
 +언뜻 보기에는 그럴듯 해 보이죠. 하지만 이 구현법에는 몇가지 문제점이 있습니다.\\
 +무엇이 문제일까요?
 +
 +스레드가 하나라면 이 코드는 잘 작동할 것입니다. 스레드가 하나 더 추가되면 어떤 일이 벌어질까요?
 +운 나쁘게 uniqueInstance가 null임을 확인하고 instance를 생성하려는 사이 다른\\ 스레드에서
 +instance를 만들어버리게 되는 상황이 발생할 수도 있습니다.
 +
 +
 +
 +===== Multi-thread problem =====
 +getInstance()를 동기화시키기만 하면 멀티스레딩과 관련된 문제가 간단하게 해결됩니다.\\
 +다음의 코드를 살펴보세요.
 +<code java>
 +public class Singleton {
 +     private static Singleton uniqueInstance;
 +
 +     private Singleton() {}
 +
 +     public static synchronized Singleton getInstance() {
 +         if (uniqueInstance == null) {
 +             uniqueInstance = new Singleton();
 +         }
 +         return uniqueInstance;
 +     }
 +}
 +</code>
 +이렇게 하면 문제가 해결되겠지만, 동기화를 하면 속도 문제가 생기지 않을까요?\\
 +좋은 지적입니다. 그리고 조금 더 생각해 보면 동기화를 하기가 정말 아깝다는 느낌이 들 수도 있습니다.\\
 +사실 동기화가 꼭 필요한 시점은 이 메소드가 시작되는 때 뿐입니다. 바꿔 말하자면, 일단 uniqueInstance\\
 +변수에 Singleton 인스턴스를 대입하고 나면 굳이 이 메소드를 동기화된 상태로 유지시킬 필요가 없다는 거죠.\\
 +첫 번째 과정을 제외하면 동기화는 불필요한 오버헤드만 증가시킬 뿐입니다.
 +
 +
 +===== Alternative =====
 +**더 효율적인 방법은 없을까요?**\\
 +
 +대부분의 자바 애플리케이션에서 싱글턴이 다중 스레드 환경에서 돌아갈 수도 있도록 만들어야 합니다.\\
 +하지만 getInstance()메소드를 동기화시키려면 적지 않은 대가를 치뤄야 합니다. 혹시 다른 방법은 없을까요?\\
 +
 +몇가지 방법을 생각해 볼 수 있을 겁니다.
 +
 +**1.getInstance()의 속도가 그리 중요하지 않다면 그냥 둡니다.**\\
 +그래도 됩니다. getInstance()메소드가 애플리케이션에 큰 부담을 주지 않는다면 그냥 놔눠도 됩니다.\\
 +getInstance()를 동기화시키는 게 그리 어려운 일도 아니고, 효율 면에서도 괜찮을 수 있습니다.\\
 +메소드를 동기화하면 성능이 100배정도 저하된다는 것은 기억해 둡시다. 만약 getInstance()가 애\\
 +플리케이션에서 병목으로 작용한다면 다른 방법을 생각해봐야 합니다.
 +
 +**2.인스턴스를 필요할 때 생성하지 말고, 처음부터 만들어 버립니다.**\\
 +애플리케이션에서 반드시 Singleton의 인스턴스를 생성하고, 그 인스턴스를 항상 사용한다면, 또는\\
 +인스턴스를 실행중에 수시로 만들고 관리하기가 성가시다면 다음과 같은 식으로 처음부터 Singleton\\
 +인스턴스를 만들어버리는 것도 괜찮은 방법입니다.
 +
 +<code java>
 +public class Singleton {
 +     private static Singleton uniqueInstance = new Singleton();
 +
 +     private Singleton() {}
 +
 +     public static Singleton getInstance() {
 +         return uniqueInstance;
 +     }
 +}
 +</code>
 +
 +이런 접근법을 사용하면 클래스가 로딩될 때 JVM에서 Singleton의 유일한 인스턴스를 생성해 줍니다.\\
 +JVM에서 유일한 인스턴스를 생성하기 전에는 그 어떤 스레드도 uniqueInstance를 정적변수에 접근할 수\\
 +없습니다.
 +
 +**3."DCL(Double-Checking Locking)"을 써서 getInstance()에서 동기화되는 부분을 줄입니다.**\\
 +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) {
 +                     uniqueInstance = new Singleton();
 +                }
 +            }
 +        }
 +        return uniqueInstance;
 +    }
 +}
 +</code>
 +
 +인스턴스를 생성하기에 앞서 인스턴스가 있는지 확인하고, 없으면 동기화된 블럭으로 들어갑니다.\\
 +이렇게 하면 처음에만 동기화가 되겠죠. 블럭으로 들어온 후에도 다시 한 번 변수가 null인지 확인\\
 +한 다음 인스턴스를 생성합니다. **volatile**키워드를 사용하면 멀티스레딩을 쓰더라도 uniqueInstance\\
 +변수가 Singleton인스턴스로 초기화되는 과정이 올바르게 진행되도록 할 수 있습니다.\\
 +
 +하지만 DCL을 이용할 경우 몇가지 주의할 점이 있습니다.\\
 +  - DCL을 사용하는 방법은 자바2 버전 5(자바 1.5)보다 전에 나온 버전에서는 쓸 수 없습니다.(volatile)
 +  - 클래스 로더가 여러개 있으면 싱글턴이 제대로 작동하지 않고, 여러개의 인스턴스가 생길 수 있습니다.
 +  - 1.2버전보다 전에 나온 JVM을 사용하는 경우에는 가비지 컬렉터 관련 버그((자바 1.2가 나오기 전까지는 가비지 컬렉터의 버그 때문에 싱글턴에 대한 전역 레퍼런스가 없는 경우에 아직 다 쓰지도 않는 싱글턴이 가비지 컬렉터에 의해 제거되는 일이 있었습니다. 즉, 싱글턴을 만들 수는 있지만 그 싱글턴에 대한 유일한 레퍼런스가 싱글턴 자체에만 있는 경우에는 가비지 컬렉터에 의해 그 인스턴스가 제거될 수도 있었죠. 싱글턴이 제거되고 나면 getInstance()를 호출했을 때 갓 만들어진 새 싱글턴이 리턴되기 때문에 아주 골치아픈 버그가 생길 수 있었습니다. 조금 전까지 잘 쓰고 있었는데, 갑자기 상태가 초기값으로 리셋되거나 네트워크 연결이 리셋되는 것 같은 이상한 일들이 벌어지곤 했습니다. \\ 하지만 자바 1.2부터는 이 버그가 수정돼서 전역 레퍼런스가 없어도 가비지 컬렉터에 의해 제거되는 일은 생기지 않습니다. 피치 못할 사정이 있어서 자바 1.2가 나오기 전에 나왔던 JVM을 사용해야 한다면 이 문제를 잘 기억해 두는 것이 좋습니다. 하지만 1.2 이후 버전을 사용한다면 괜히 가비지 컬렉터가 싱글턴을 잡아먹지는 않을까 하는 걱정을 할 필요가  없습니다.))때문에 싱글턴 레지스트리를 사용해야 할 수도 있습니다.
  
  
  

QR Code
QR Code study:java:design_pattern:singleton (generated for current page)