본문 바로가기
public void static main()/Lecture

[Design Patterns] Singleton Pattern feat. 백기선 강사님

by 햄리뮤 2022. 8. 30.
반응형
https://twitter.com/e_eliie/status/807535726124417024

하루 1강씩이라도 듣자는 의지를 계속 실천하고있따!!!!
할수있다!! 잘한다 잘한다 잘한다
자! 오늘의 복습! 시작!

https://www.digitalocean.com/community/tutorials/java-design-patterns-example-tutorial

Singleton Pattern이 뭐야?

- 인스턴스를 오직 한개만 제공하는 클래스!

개념은 알겠고... 싱글톤 패턴은 언제 써...?

- 시스템 런타임, 환경세팅에 대한 정보등 인스턴스가 여러개 일 때 문제가 생길 수 있을때 싱글톤 패턴을 써!
ex) 게임을 예를 들면! 한 계정에 하나의 세팅이 있어야하자나! 한번 세팅 해놨는데 매번 로그인할때마다 세팅이 바뀌면 화난다고! (DB에서 부르지 않는다는걸 가정하자...!)

이제 코드를 보여줘! 어떻게 쓰면 되는거야!?

싱글톤 패턴을 사용하는 방법은 여러가지가 있어! 그중 단계별로 설명해볼께! 모든 것은 강의에 있는 내용이라구!

[첫번째 방법!]

public class Singletone {

	private static Singleton instance;
    
    // [1] 생성자를 왜 private으로 만들었지?
    private Singleton() {
    }

	// [2] 메소드도 static으로??
	public static Singleton getInstance() {
    	if (instance == null) {
        	instance = new Singleton();
        }
        return instance;
    }
}


[1] 생성자를 private으로 만든 이유가 뭘까?
- 오직 한개의 인스턴스만 접근하기 위해서 생성자의 접근을 제한했어! -> public이면 여기서도 호출 저기서도 호출!

[2] getInstance() 메소드에 static을 붙인 이유는?
- 생성자가 private이기 때문에 글로벌하게 접근할 수 있도록 static으로 선언했어! static으로 선언했다는 것은 JVM 클래스 영역에 생성되어서 글로벌하게 사용할 수 있다고!
- 처음 만들어진 이후에는 null이 아니기 때문에 단 하나의 instance만 리턴해!

[3] 그럼 getInstance()는 멀티 스레드 환경에 안전해?
- 아니! 안전하지 않아! 두개의 스레드가 거의 동시에 들어와서 두 스레드가 instance == null 일 경우가 있어! 그래서 두개의 스레드가 new Singleton() 을 리턴하게 된다고!

즉 위의 코드는 멀티 스레드 환경에서 한개의 인스턴스를 보장할 수 없다!

[두번째 방법]
동기화(synchronized)를 사용해 멀티 스레드 환경에 안전하게 만드는 방법

public class Singleton {
	private static Singleton instance;
    
    private Singleton() {
    }
    
    // [1] synchronized가 뭐야... 몰라 무서워
    public static synchronized Singleton getInstance() {
    	if (instance == null) {
        	instance = new Singleton02();
        }
        return instance;
    }
}

[1] synchronized 란!?
- 메소드에 한번에 한 스레드만 들어오게 만들어주는 마법의 단어! 하지만 단점이 있어!
getInstance()를 호출할 때마다 동기화 처리 작업때문에 성능에 문제가 있을 수 있어!

// synchronized를 좀~만더 알아보고싶어!
public class SynchronizedApp {
	public synchronized void one() {
    }
    
    public synchronized void two() {
    }
    
    public void three() {
    }
}

one과 two 메소드 자체에 synchronized를 설정 함으로써 해당 메소드가 한번에 하나의 thread에 의해서 불러져!
그리고 method level의 synchronized는 한 클래스 내에 정의된 모든 메소드들에 동일하게 적용됨! (이게무슨말이냐구!?)
예를들어서 A라는 thread에서 one 메소드를 사용하고있다면 two메소드를 다른 thread가(B스레드, C스레드 등등) 사용할 수 없어!
하나의 동시 객체로 인식한다고!

[2] 동기화 처리를 어떻게 하길래??
- 멀티 스레드에서 메서드 호출마다 먼저 호출한 스레드에 열쇠를 주는데 열쇠가 없는 스레드는 들어올 수 없게 만들어놓았어! (locking 이라고도 한다네! 이거좀 어려워...)
- 이 방법은 thread-safe 함을 유지하려는 목적에 비해 동기화에 대한 오버헤드가 심해!

잠깐! 오버헤드란?
프로그램의 실행흐름에서 나타나는 현상중 하나로, 프로그램의 실행 흐름 도중에 동떨어진 위치의 코드를 실행시켜야 할때, 추가적으로 시간, 메모리, 자원이 사용되는 현상!
한마디로 오버헤드는 특정 기능을 수행하는데 드는 간접적인 시간, 메모리 등 자원을 말해!

[세번째 방법]
이른 초기화 (eager initialization)을 사용하는 방법

public class Singleton {

	private static final Singleton INSTANCE = new Singleton();
    
    private Singleton() {
    
    }
    
    public static Singleton getInstance() {
    	return INSTANCE;
    }
}

[1] 이른초기화? 초기화를 빨리한다는건가?
- 맞아! 인스턴스를 사용하지 않더라도 생성하기 때문에 효율성이 떨어져!
- 클래스가 메모리에 할당되는 시점에 바아로 생성이 된다고!

[2] 만약 생성자에서 checked 예외를 던진다면?
- try-catch를 사용해서 unchecked 예외로 변환시켜야해!

잠깐! checked Exception 이란?
https://devlog-wjdrbs96.tistory.com/351
체크 예외(Checked Exception)
- RuntimeException의 하위 클래스가 아니면서 Exception 클래스의 하위 클래스들.
- 반듯이 에러 처리를 해야하는 특징을 갖고있다.
ex)
- 존재하지 않는 파일의 이름을 입력(FileNotFoundException)
- 실수로 클래스의 이름을 잘못 적음(ClassNotFoundException)

언체크 예외(Unchecked Exception)
- RuntimeException의 하위 클래스들
- 에러처리를 강제하지 않음.
- 실행중에(runtime시) 발생할 수 있는 예외.
ex)
- 배열의 범위를 벗어남(ArrayIndexOutOfBoundsException)
- 값이 null인 참조변수를 참조(NullPointerException)

[네번째 방법]
double checked locking 효율적인 동기화 블럭 만들기

public class Singleton04 {

  // volatile을 써줘야만 자바 1.5 이상부터 동작하는 double check  locking이 동작함
  private static volatile Singleton04 instance;
  private Singleton04() {
  }

  // double check locking
  // 인스턴스를 필요로하는 시점에 만들 수 있다.
  // 메소드에 synchronized를 쓰는것 보다 성능이 나음.
  public static Singleton04 getInstance() {
    // 첫번째 체크
    if (instance == null) {
      // Singleton_04.class 를 lock으로 쓰게 해줌
      synchronized (Singleton04.class) {
        // 두번째 체크
        if (instance == null) {
          instance = new Singleton04();
        }
      }
    }
    return instance;
  }
}

[1] double check locking 이라고 불리는 이유는?
- 총 2번에 걸쳐서 단 하나의 객체임을 체크하기 때문이야! 첫번째 instance가 null일 경우, 동기화 클래스 synchronized에서 한번 더 체크해! 첫번째 체크를 통과한 thread들만 동기화 블럭에 적용됨!
[2] volatile??
- 변수는 volatile 키워드로 선언해야해! 여러 스레드가 동시에 접근하게 되는 경우 메모리 장벽 특성으로 인한 싱글톤 패턴에 대해서 double checked locking (DCL) 패턴을 사용할 수 있어! 좀 어렵네...!
- 인스턴스를 main 메모리에 저장하고 읽기때문에 값 불일치 문제를 해결할 수 있어!
접근 성능은 느리지만, 변수의 접근(read, write)에 대한 정합성을 보장해줘!

[다섯번째 방법]
static inner 클래스를 사용하는 방법

public class Singleton05 {

  // 멀티 스레드 환경에서도 안전하고, getInstance가 호출 될때 인스턴스가 만들어지고 
  // lazy 로딩도 가능한 코드가 됨.
  private static class SingletonHolder {
    private static final Singleton05 SINGLETON_05 = new Singleton05();
  }

  public static Singleton05 getInstance() {
    return SingletonHolder.SINGLETON_05;
  }
}

lazy 로딩?? 지연 초기화 (lazy initialization) 이란??
- 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 기법!
[1] static final을 썼는데 지연 초기화라고 볼수있어??
- static 필드는 클래스가 처음 로딩될 때 정적인 공간에서 만들어지는데! SingletonHolder가 갖고있는 클래스가 로딩되는 시점은 getInstance()를 호출할 때 로딩되기 때문에 lazy initialization가 맞아!



우와~ 싱글톤 복습 끝!
너무 졸려서 여기까지만 복습하는걸로!!
오늘도 제 공부에 도움을 주신 멋진 지식인 파워 블로거분들 감사합니다!


** 그냥 하루하루 개인 공부한 것을 끄적 거리는 공간입니다.
이곳 저곳에서 구글링한 것과 강의 들은
내용이 정리가 되었습니다.
그림들은 그림밑에 출처표시를 해놓았습니다.
문제가 될시 말씀해주시면 해당 부분은 삭제 하도록하겠습니다. **
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com

https://donggu1105.tistory.com/175

[개발용어] 오버헤드(overhead)란?

개발관련 유투브를 보다가 오버헤드란 단어가 나왔다. 뭘까? 검색해보았다. In computer science, overhead is any combination of excess or indirect computation time, memory, bandwidth, or other resources..

donggu1105.tistory.com

https://enumclass.tistory.com/169

Java의 동기화 및 Locking 기법 들 (Synchronized, ReentrantLock, Semaphore, Atomic Package, varHandle)

알고자 하는 것 : Synchronized keyword, ReentrantLock, Semaphore, Atomic, varHandle Synchronized https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html synchronized의 경우에는..

enumclass.tistory.com

https://devlog-wjdrbs96.tistory.com/351

[Java] Checked Exception vs Unchecked Exception 정리

체크 예외와 언체크 예외(Checked, Unchecked Exception) 자바의 예외는 크게 3가지로 나눌 수 있습니다. 체크 예외(Checked Exception) 에러(Error) 언체크 예외(Unchecked Exception) 자바에서 에러 , 예외 관련..

devlog-wjdrbs96.tistory.com





반응형

댓글