ㅇTL
Design pattern - Singleton 본문
Design patter
= 소프트웨어 설계할 때 자주 발생하는 문제들에 재사용할 수 있는 훌륭한 해결책
= 가이드로 사용할 수 있는 모델 혹은 설계
=> 특정 상황에서 일반적인 문제에 대한 입증된 솔루션 !
- 이미 해결된 문제를 처리하기 위한 툴킷을 제공
- 소프트웨어 문제를 어떻게 해결할지 생각하는데 도움을 줌
- 23개의 디자인 패턴을 정리하고, 다음 3가지로 분류함
1. Creational(생성) : 객체 생성과 관련된 패턴
2. Structural(구조) : 클래스나 객체를 조합해 더 큰 구조를 만드는 패턴
3. Behavioral(행위) : 객체나 클래스 사이의 알고리즘이나, 책임 분재에 관련된 패턴
Singleton
= 한 클래스에 대해 객체를 하나만 !! 생성할 수 있도록 한 것 -> 어디서든지 사용 가능
1. constructor은 private으로 해서 생성할 수 없게 하고, (-> 클래스 내부에서만 클래스의 인스턴스 생성 가능)
2. 멤버변수로 해당 클래스 객체를 static으로 가진다
3. 그리고 객체가 null일때 객체 만드는 static 함수 만들어서 해당 객체 한번만 생성될 수 있도록 한다 !
: 전역변수를 사용하지 않고 객체를 하나만 생성하도록 하며, 이 객체 어디서든지 참조할 수 있도록 하는 패턴 !
-> 단 하나의 인스턴스를 생성해 (전역변수처럼) 사용하는 디자인 패턴
사용예시 : 로그인, 캐시, 레지스터리 처리 객체..
장점
- 메모리 낭비 방지 가능
- 다른 클래스와 데이터 공유 편하게 가능
단점
- 기능 검증 및 수정이 어렵
- MultiThreading 환경에서 동기화처리 하지않으면 문제 발생 가능
예시
public class Logger{
private static Logger instance; // 하나만 정적으로 만듬
private Logger() P{} // 생성자는 private !!
public static Logger getInstance(){ //static변수에 대한 함수이므로 static !
if(instance==null) //아무것도 없을때만 !!
instance=new Logger();
return instance;
}
(-> 객체가 필요한 상황이 되기 전까지는 객체를 생성하지 xx)
**문제점**
: 여러 쓰레드가 동시에 접근할 때 문제가 생긴다!
저기서는
if(instance=null)여기서 조건문이 동시에 두번 돌 수 있기때문에 하나의 인스턴스가 아닌 여러개의 인스턴스가 발생 할 위험이 있다 !.
**해결 방법**
1. Simple Locking
: synchronized를 사용하여 간단히 getInstance() 메소드를 Lock하는 방법
//1. 함수에 synchronized 쓴다
public static synchronized Logger getInstance(){
if(instance==null) //아무것도 없을때만 !!
instance=new Logger();
return instance;
}
//2. 그 부분에만 동기화 씌운다
public static Logger getInstance(){
synchonized(Logger.class){
if(instance==null) //아무것도 없을때만 !!
instance=new Logger();
}
return instance;
}
!! synchronized(Classname.class){ 씌울 부분 } !!
* https://jgrammer.tistory.com/entry/Java-혼동되는-synchronized-동기화-정리
2. Double-Checked Locking
: volatile을 사용하여 Lock
//함수 안에..
if(instance==null{
synchonized(Logger.class){
if(instance==null) //아무것도 없을때만 !!
instance=new Logger();
}
}
// 그리고 변수는 이렇게 선언
private volatile static Logger instance;
- null 을 두번물어본다 (double check) -> 두번째꺼에만 synchronized를 걸어준다
- 변수에 volatile를 적는다 (필수) ; 일단 간략하게 설명하자면 main memory가 있고 각 스레드 마다 working memory가 있다. main memory <-> working memory 이렇게 두 메모리간 데이터 이동이 있으며, 두 메모리간 동기화가 진행되는 동안 빈틈이 생기게 되기 때문에 volatile을 쓰는 것이다.
volatile 키워드 없이 DCL을 구현하면 생성이 되다만 객체를 다른 스레드에서 참조 할 수 있는 문제가 있다.
!! private volatile static !!
각 스레드가 동작하며 값을 메인메모리에서 읽어와서 cpu cache에 저장한다
이때 변수 값 불일치 문제가 생길 수 있다
volatie은 변수를 main memory에 저장하겠다는 걸 명시하기 위해 사용한다
리드 거기서하고 라이트할때도 메인메모리에 작성한다
3. Eager Initialization
: 클래스 참조 시, 객체를 생성하여 충돌 방지하는 방법
= Class를 최초로 참조할 때 static변수이므로 자동으로 변수가 생김! (이거말고는 객체 생성 방법 xx)
public class Singleton{
private Singleton(){ }
private static Singleton instance = new Singleton();
~~
public static Singleton getInstance(){
return instance;
}
}
걍 변수 생성할 때 바로 초기화 해버리는것!
- class가 참조될 때 바로 객체를 생성하기 때문에 오버헤드가 작다.
-문제는 클라이언트가 사용하지 않더라도 무조건 생성된다는 점
'2-1 > 객체지향 - java' 카테고리의 다른 글
14. Collections, Maps, Iterators (0) | 2022.06.19 |
---|---|
디자인패턴 2 - Observer & Decorator (0) | 2022.06.18 |
14- ArrayList , Generics (0) | 2022.06.13 |
Interfaces and Inner Classes (0) | 2022.06.02 |
19- Threads (0) | 2022.05.31 |