<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>응미 개발블로그</title>
        <link>https://velog.io/</link>
        <description>⭐️조금씩이라도 꾸준히⭐️</description>
        <lastBuildDate>Fri, 20 Aug 2021 11:44:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>응미 개발블로그</title>
            <url>https://images.velog.io/images/hihih_dev/profile/d9aac820-dd3b-4098-b39a-6bb2e97baf57/20210820_184855.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 응미 개발블로그. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hihih_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Design Pattern] 싱글톤 패턴 (Singleton Pattern)]]></title>
            <link>https://velog.io/@hihih_dev/DesignPattern-%EC%8B%B1%EA%B8%80%ED%86%A4%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@hihih_dev/DesignPattern-%EC%8B%B1%EA%B8%80%ED%86%A4%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 20 Aug 2021 11:44:01 GMT</pubDate>
            <description><![CDATA[<h2 id="singleton-pattern-이란">Singleton Pattern 이란?</h2>
<p>싱글톤 패턴은 앱이 시작될때 어떤 최초 한번만 메모리를 할당하고(static), 그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴이다. </p>
<p>생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나고, 최초 생성이후에 호출된 생성자는 최초에 생성한 객체를 반환한다. </p>
<p>즉, 싱글톤 패턴은 단 하나의 인스턴스를 생성해 사용하는 디자인패턴이다. </p>
<p><strong>인스턴스가 필요할 때 똑같은 인스턴스를 만들어 내는 것이 아니라, 기존 인스턴스를 사용하게 한다.</strong></p>
</br>

<h2 id="singleton-pattern-을-사용하는-이유">Singleton Pattern 을 사용하는 이유</h2>
<p>① 고정된 메모리 영역을 얻으면서 한번의 new로 인스턴스를 사용하기 때문에 메모리 낭비를 방지할수 있다. </p>
<p>② 싱글톤으로 만들어진 클래스의 인스턴스는 전역 인스턴스이기 때문에 다른 클래스의 인스턴스들이데이터를 공유하기 쉽다.
<span style="color: green">Ex. DB Manager 처럼 공통된 객체를 여러개 생성해서 사용해야 하는 상황에서 많이 사용된다.</span></p>
<p>③ 안드로이드 앱 같은 경우 각 Activity나 클래스별로 주요 클래스들을 일일이 전달하기 번거롭기 때문에 싱글톤 클래스를 만들어 어디서나 접근하도록 설계하는 것이 편하다.</p>
<p><strong>즉, 인스턴스가 절대적으로  한개만 존재하는 것을 보증하고 싶을때 사용한다.</strong></p>
</br>

<h2 id="singleton-pattern-의-문제점">Singleton Pattern 의 문제점</h2>
<p>멀티쓰레드 환경에서 동기화 처리를 하지않으면 인스턴스가 두개가 생성된다던지 하는 경우가 발생할 수 있다. </p>
</br>

<h2 id="singleton-pattern-의-종류">Singleton Pattern 의 종류</h2>
<h3 id="span-stylecolor-green1-eager-initialization-이른-초기화-방식span"><strong><span style="color: green">(1) Eager Initialization (이른 초기화 방식)</span></strong></h3>
<pre><code class="language-java">public class TestMaanger {
   // private static으로 선언하기
   private static TestManager instance = new TestManager();

   // 생성자
   private TestMaanger() { }

   // 인스턴스 리턴하기
   public static TestManager getInstance() {
     return instance;
   }
}</code></pre>
</br>
싱글톤 패턴의 가장 기본적인 유형인 Eager Initialization 방식이다.

<p>먼저 클래스 내에 전역변수로 instance 변수를 생성하고 private static을 사용하여 인스턴스화에 상관없이 접근이 가능하면서, 동시에 private 접근 제어 키워드를 사용해 TestManager.instance 에 바로 접근할 수 없도록 한다. </p>
<p>또 생성자에도 private 접근 제어 키워드를 붙여 다른 클래스에서 new TestManager(); 방식으로 새로운 인스턴스를 생성하는 것을 방지한다.</p>
<p>오로지 정적메서드인 getInstance()메서드를 이용해서 인스턴스를 접근하도록 하여, 동일 인스턴스를 사용하는 기본 싱글톤 원칙을 지키게 한다. </p>
<p>Eager Initialization 방식은 싱글톤 객체를 미리 생성해놓는 방식이다.</p>
<p><span style="color: green"><strong>장점</strong></span>은 static으로 생성된 변수에 싱글톤 객체를 선언했기 때문에, 클래스 로더에 의해 클래스가 로딩될 때 싱글톤 객체가 생성된다. </p>
<p>또 클래스 로더에 의해 클래스가 최초 로딩될 때 객체가 생성됨으로 Tread-safe 하다.</p>
<p><span style="color: green"><strong>단점</strong></span>은 싱글톤 객체 사용유무와 관계없이 클래스가 로딩되는 시점에 항상 싱글톤 객체가 생성되고, 메모리를 잡고 있기 때문에 비효율적일 수 있다. </p>
</br>

<h3 id="span-stylecolor-green2-lazy-initialization-늦은-초기화-방식span"><strong><span style="color: green">(2) Lazy Initialization (늦은 초기화 방식)</span></strong></h3>
<pre><code class="language-java">public class TestManager {
   // private static으로 선언하기
   private static TestManager instance;

   // 생성자
   private TestManager() { }

   // 인스턴스 리턴하기
   public static TestManager getInstance() {
      if(instance == null) {
         instance = new TestManager();
      }
      return instance;
   }
}</code></pre>
</br>
Eager Initialization과 정반대로 클래스가 로딩되는 시점이 아닌, 클래스의 인스턴스가 사용되는 시점에서 싱글톤 인스턴스를 생성한다. 

<p>즉, 사용 시점까지 싱글톤 객체 생성을 미루기 때문에 사용전까지 메모리를 점유하지 않는다.</p>
<p><span style="color: green"><strong>장점</strong></span>은 싱글톤 객체가 필요할 때 인스턴스를 얻을 수 있어 메모리 누수를 방지할 수 있다. 
(Eager Initialization 방식의 단점 보완)</p>
<p><span style="color: green"><strong>단점</strong></span>은 만약 멀티 쓰레드 환경에서 여러곳에서 동시에 getInstance()를 호출할 경우, 인스턴스가 두번 생성될 여지가 있다. 즉, 멀티 쓰레드 환경에서는 싱글톤 철학이 깨질 수 있다. </p>
</br>

<h3 id="span-stylecolor-green3-thread-safe-lazy-initialization-스레드-안전한-늦은-초기화-방식span"><strong><span style="color: green">(3) Thread safe Lazy Initialization (스레드 안전한 늦은 초기화 방식)</span></strong></h3>
<pre><code class="language-java">public class TestManager {
   // private static으로 선언하기
   private static TestManager instance;

   // 생성자
   private TestManager() { }

   // 인스턴스 리턴하기
   public static synchronized TestManager getInstance() {
      if (instance == null) {
          instance = new TestManager(0;
      }
      return instance;
   }
}</code></pre>
</br>
Lazy Initialization 방식에서 Thread-Safe 하지 않다는 단점을 보완하기 위해, 멀티 쓰레드 환경에서 쓰레드들이 동시 접근하는 동시성을 synchronized 키워드를 이용해 해결한다.

<p><span style="color: green"><strong>장점</strong></span>은 Lazy Initialization 방식에서 Thread-Safe 하지 않은 점을 보완한다.</p>
<p><span style="color: green"><strong>단점</strong></span>은 synchronized 키워드를 사용할 경우, 자바 내부적으로 해당 영역이나 메서드를 lock, unlock 처리하기 때문에 내부적으로 많은 비용이 발생한다.</p>
<p>따라서 많은 쓰레드들이 getInstance()를 호출하게 되면 프로그램 전반적인 성능저하가 발생한다.
</br></p>
<h3 id="span-stylecolor-green4-thread-safe-lzy-initialization--double-checked-locking-방식span"><strong><span style="color: green">(4) Thread safe Lzy Initialization + Double-Checked locking 방식</span></strong></h3>
<pre><code class="language-java">public class TestManager {
   // private static으로 선언하기
   private static TestManager instance;

   // 생성자
   private TestManager() { }

   // 인스턴스 리턴하기
   public static TestManager getInstance() {
      if (instance == null) {
          synchronized (TestManager.class) {
              if (instance == null) {
                  instance = new TestManager();
              }
          }
      }
      return instance;
   }
}</code></pre>
</br>
Thread safe Lzy Initialization 방식은 많은 쓰레드들이 동시에 synchronized 처리된 메소드에 접근하면 성능저하가 발생한다.

<p>이를 완화하기 위해 Double-Checked locking 기법을 사용한다.</p>
<p>첫번째 if문에서 instance가 null인 경우 synchronized 블럭에 접근하고 한번 더 if문으로 instance가 null인지를 체크한다.</p>
<p>두번 모두 다 instance가 null인 경우에만 new를 통해 인스턴스화 시킨다.</p>
<p>그 후에는 instance가 null이 아니기 때문에 synchronized 블럭을 타지 않을 것이다.</p>
<p>이런 Double-Checked locking 기법을 통해 성능저하를 보완할 수 있다.
</br></p>
<h3 id="span-stylecolor-green5-initialization-on-demand-holder-idiom-holder에-의한-초기화span"><strong><span style="color: green">(5) Initialization on demand holder idiom (holder에 의한 초기화)</span></strong></h3>
<pre><code class="language-java">public class TestManager {
   // 생성자
   private TestManager() { }

   // 인스턴스를 리턴할 Holder 클래스 생성하기
   private static class TestManagerHolder {
      private static final TestManager instance = new TestManager();
   }

   public static TestManager getInstance() {
      return TestManagerHolder.instance;
   }
}</code></pre>
</br>
이 방법은 클래스안에 클래스(Holder)를 두어 JVM의 클래스 로더 매커니즘과 클래스가 로드되는 시점을 이용한 방법이다.

<p>Lazy Initialization 방식을 가져가면서 Thread간 동기화 문제를 동시에 해결할 수 있다. </p>
<p>중첩클래스 Holder는 getInstance()메서드가 호출되기 전에는 참조되지 않으며, 최초로 getInstance()메서드가 호출될 때, 클래스 로더에 의해 싱글톤 객체를 생성하여 리턴한다. </p>
<p>우리가 알아야 할 것은 Holder 안에 선언된 instance가 static이기 때문에, 클래스 로딩 시점에 한번만 호출된다는 점을 이용한 것이다. 또 final을 사용해서 다시 값이 할당되지 않도록 한다.</p>
<p>현재까지 가장 많이 사용되는 방법이다.</p>
</br>
</br>
</br>]]></description>
        </item>
    </channel>
</rss>