-
Java의 Singleton Pattern에 대하여Java 2021. 5. 26. 18:17
싱글톤 패턴이란?
싱글톤 패턴은 프로그램 어디에서든지 접근 가능하고 프로그램에서 단 하나만 존재하는 객체를 만드는 패턴입니다. 싱글톤 패턴은 아주 다양하게 사용되는데, Android에서 SharedPreference와 같은 저장소도 싱글톤 패턴으로 구현됩니다.(저장소인데 프로그램에서 여러 개 존재하면 안 되겠죠?)
싱글톤 패턴을 구현하는 방법은 여러 가지인데, 멀티 스레드 환경에서 동시성에 관한 문제 때문에 이를 해결하기 위한 기법들이 존재합니다. 객체를 생성할 때 여러 스레드가 동시에 접근하면 1개가 아니라 여러 개가 생성될 수 있는 위험이 있기 때문이죠.
구현 방법
Class SingletonTest { private static SingletonTest instance; private int value; // 외부에서 생성자를 통해 생성하는 것을 막습니다 private SingletonTest(int value) { this.value = value; } public SingletonTest getInstance(int value) { if(instance == null) { instance = new SingletonTest(value); } return instance; } }
가장 먼저 단순히 클래스 내부에서 static 변수를 선언하고 이를 호출하는 곳에 return 하는 형식의 구현 방법입니다. 이 클래스의 생성자를 private로 제한함으로써 외부에서 직접적으로 instance를 만드는 것을 제한하고, getInstance만을 사용해서 생성할 수 있도록 하는 것입니다. 이때, 한 번도 instance가 만들어진 적이 없다면 내부적으로 생성자를 호출해서 instance를 만들어줍니다.
앞서 언급한 것처럼, 이 방법으로 구현했을 때는 멀티 스레드 환경에서 문제가 될 수 있습니다. 최근 어플리케이션들은 대부분 멀티 스레드 환경일 텐데요, 여러 스레드가 동시에 getInstance에 접근한다면 동시성 문제가 발생해 여러 개의 instance가 생길 수 있습니다. 이에 대응하기 위해 코드를 일부 수정할 수 있는데요.
Class SingletonTest { private static SingletonTest instance; private int value; // 외부에서 생성자를 통해 생성하는 것을 막습니다 private SingletonTest(int value) { this.value = value; } public static synchronized SingletonTest getInstance(int value) { if(instance == null) { instance = new SingletonTest(value); } return instance; } }
Thread-safe 하도록 임계 구역을 만들어주는 방법입니다. 자바에서는 synchronized를 사용해서 임계 구역을 설정할 수 있는데요, 하지만, 성능이 비교적 떨어진다는 단점이 있습니다. 그래서 가장 많이 쓰이는 방법이 바로, Lazy holder패턴입니다.
Class SingletonTest { // 외부에서 생성자를 통해 생성하는 것을 막습니다 private SingletonTest() {} private static class InnerSingletonTest() { static final SingletonTest instance = new SingletonTest(); } public SingletonTest getInstance(int value) { return InnerSingletonTest.instance(value); } }
Lazy Holder 패턴을 이용한 구현은 private static class의 특성을 사용한 방법입니다. private static class는 static class이지만 바로 메모리에 올라가지 않고, 처음 호출될 때 클래스 로더에 의해서 초기화됩니다. 이때, 내부적으로 synchronized 메서드를 통해 초기화되기 때문에 Thread-safe 하게 동작합니다.
참조 문헌
Dive into Design Patterns / Singleton
Initialization-on-demand holder idiom
'Java' 카테고리의 다른 글
Abstract Class와 Interface의 차이 (0) 2021.04.13 Java에서 동시성 관리 - Synchronization (0) 2020.12.29 Java GC와 Object간 Reference (0) 2020.10.18 Java로 구현하는 DFS 알고리즘 (0) 2020.02.24