1. Singleton pattern 이란?
1) 개념
프로그래밍을 하다보면 단 하나만 존재하는 인스턴스가 존재할 수 있다.
예를들어 회사에 대한 정보를 저장하는 클래스를 생성한다고 가정하면 회사명은 하나만 존재하면 된다.
이렇게 인스턴스가 오직 1개만 생성되야 하는 경우에 사용하는 패턴이다.
싱글턴 패턴을 구현할 때 멀티 스레딩 환경에서도 동작이 가능해야 하기 때문에 Thread-safe가 보장되어야 한다.
Thread-safe 란?
멀티 스레드 환경에서 동작해도 원래 의도한 형태로 동작하는 코드
2) Eager Initalzation (이른 초기화 방식)
static 키워드의 특징을 이용하여 프로그램이 시작하는 시점에서 정적 바인딩을 통해 해당 공유 인스턴스를 메모리에 올려 사용하는 방식이다.
2.1) Company.java
static 키워드로 instance 객체를 생성한 후 해당 인스턴스를 가져올 때 마다 static 메서드인 getInstance를 통해 가져오도록 설정한다.
public class Company {
private static Company instance = new Company();
private Company() {
}
public static Company getInstance() { //외부에서 가져오기 위해서 static으로 생성
return instance;
}
}
2.2) CompanyTest.java
인스턴스를 가져오고 싶을 경우 직접 호출을 통해 해당 값을 바로 가져올 수 있다.
2개의 객체를 생성하고 인스턴스를 가져올 경우 출력하면 동일한 값이 출력된다.
public class CompanyTest {
public static void main(String[] args) {
Company company1 = Company.getInstance();
Company company2 = Company.getInstance();
System.out.println("company1: " + company1);
System.out.println("company2: " + company2);
}
}
2.3) 출력 결과
3) Lazy initialization (늦은 초기화 방식)
이른 초기화 방식과 정반대로 클래스가 로드 되는 시점이 아닌 인스턴스가 필요한 시점에 요청할 경우 동적 바인딩을 통해 인스턴스를 생성하는 방식이다. Thread-safe를 만족 시키기 위해서 synchronized 키워드를 사용한다.
사용 전까지 메모리를 차지하지 않는 장점이 있다.
3.1) Company.java
public class Company {
private static Company instance;
private Company() {
}
public static synchronized Company getInstance() { //외부에서 가져오기 위해서 static으로 생성
if(instance == null) {
instance = new Company();
}
return instance;
}
}
4) Lazy Initialization + Double Checking Locking(DCL, Thread-safe)
위 방법은 많은 thread 들이 인스턴스를 호출할 경우 성능 저하가 발생하기 때문에 이를 개선한 방법이다.
이 방식은 인스턴스가 생성되지 않은 경우에만 동기화 블럭이 실행되게끔 구현하는 방식이다.
4.1) Company.java
volatile 키워드는 멀티스레딩 환경에서 인스턴스 초기화 하는 과정이 올바르게 진행될 수 있도록 설정해 준다.
첫번 째 if문에서 인스턴스가 생성되지 않은 경우 synchronized 블럭에 접근한 후 한번 더 존재 유무를 체크한 후 없는 경우 인스턴스를 생성한다.
이후 재 호출될 경우 인스턴스가 존재하기 때문에 synchronized 블럭에 접근하지 않아 성능 저하를 예방할 수 있다.
public class Company {
private volatile static Company instance;
private Company() {
}
public static Company getInstance() { //외부에서 가져오기 위해서 static으로 생성
if(instance == null) {
synchronized (Company.class) {
if(instance == null) {
instance = new Company();
}
}
}
return instance;
}
}
2. 간단한 예제 풀이
1) 문제
카드 회사가 있습니다. 카드회사는 유일한 객체이고 회사 카드를 발급하면 항상 고유번호가 자동으로 생성됩니다.
10001부터 시작하여 카드가 생성될 떄 마다 10002, 10003식으로 증가 됩니다.
다음 코드가 수행 되도록 Card 클래스와 CardCompany 클래스를 구현하세요
2) 메인 함수 정보
3) 문제 풀이
3.1) Card.java
public class Card {
private static int cardNum = 10001;
private int userCardNum;
public Card() {
userCardNum = cardNum;
cardNum++;
}
public int getCardNumber() {
return userCardNum;
}
}
3.2) CardCompany.java
public class CardCompany {
public static CardCompany instance = new CardCompany();
private CardCompany() {}
public static CardCompany getInstance() {
if(instance == null) {
instance = new CardCompany();
}
return instance;
}
public Card createCard() {
Card card = new Card();
return card;
}
}
[참조]
패턴 방식: limkydev.tistory.com/67
패턴 방식: medium.com/webeveloper/%EC%8B%B1%EA%B8%80%ED%84%B4-%ED%8C%A8%ED%84%B4-singleton-pattern-db75ed29c36
'Language > JAVA' 카테고리의 다른 글
[JAVA] 배열(Array), 참조 배열(Reference Array) 개념 및 구현 (0) | 2021.02.17 |
---|---|
[JAVA] static 변수, 메서드 개념 및 구현 (0) | 2021.02.16 |
[JAVA]this 키워드 개념 및 구현 (0) | 2021.02.15 |
[JAVA]접근 제어자(Access modifier) 개념 및 구현 (0) | 2021.02.14 |
[JAVA] 참조 자료형(Reference data type) 개념 및 구현 (0) | 2021.02.14 |
공부&일상 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 질문은 언제나 환영입니다😊