싱글톤 패턴은 오직 하나의 유일한 객체를 만들기 위한 코드 패턴이다.
다시 말해, 여러가지 이유를 이점으로 . 객체가 필요할 때 똑같은 객체를 새로 만들지 않고,기존의 객체를 가져와 활용하는 기법을 말한다.
싱글톤 패턴을 사용하는 이유
1. 메모리 측면의 이점
싱글톤 패턴을 사용하게 된다면 한개의 인스턴스만을 고정 메모리 영역에 생성하고
추후 해당 객체를 접근할 때 메모리 낭비를 방지할 수 있다.
2. 속도 측면의 이점
생성된 객체를 사용할 때는 이미 생성된 객체를 활용하여 속도 측면에 이점이 있다.
3. 데이터 공유가 쉽다
*_전역으로 사용하는 객체이기 때문에 다른 여러 클래스에서 데이터를 공유하며 사용할 수 있다.
하지만 동시성 문제가 발생할 수 있어 이점은 유의하여 설계하여야 한다.
싱글톤 패턴를 쉽게 이해하기 위해 *_전역변수에 대해서 예를 들겠다.
개발자들이 전역변수라는 걸 만들어 사용하는 이유는, 똑같은 데이터를 메소드마다 지역 변수로 선언해서사용하면 무의미한 낭비이기 때문에,
전역에서 한번만 데이터를 선언하면 가져와서 사용하기 효율적이기 때문이다.
이러한 개념을 그대로 클래스에 대입한 것이 싱글톤 패턴 이라고 이해하면 된다.
따라서 보통 싱글톤 패턴이 적용된 객체가 필요한 경우는 그 객체가 리소스를 많이 차지하는 역할을 하는 무거운 클래스일때 적합하다.
싱글톤 패턴 구현하기
public class Singleton{
// 1개만 존재해야 하는 객체이므로 static으로 선언
private static Singleton instance;
//private 생성자로 외부에서 객체 생성을 막아야함.
private Singlngton(){
}
// 외부에서는 getInstance()로 instance 반환
public static Singleton geInstance(){
//instance가 null일때만 생성
if(instande == null){
instance = new Singleton();
}
return instance;
}
}
싱글톤 패턴의 기본적인 구현방법은 다음과 같다.
먼저 private static으로 Singleton객체의 instance를 선언하고, instance() 메소드가 처음 실행 될 떄만
하나의 instance가 생성되고 그 후에는 이미 생성되어진 instance를 return 하는 방식으로 진행이 된다.
핵심은 private로 된 기본 생성자이고, 생성자를 private으로 생성하며 외부에서 새로운 객체의 생성을 막아야한다.
//같은 instance인지 Test
public class Application{
public static void main(String[] args){
Singleton st1 = Singleton.getInstance();
Singleton st2 = Singleton.getInstance();
System.out.println(st1);
System.out.println(st2);
}
}
// 결과
//org.example.Singleton@6d06d69c
//org.example.Singleton@6d06d69c
//
싱글톤 객체를 생성하는 위의 코드를 실행해보면 두 객체가 하나의 인스턴스를 사용하여
같은 주소 값을 출력하는 것을 확인할수 있다.
Multi-thread에서의 Singleton
multi-thread환경에서 싱글톤을 사용한다면, 몇가지 문제가 발생할 수 있다.
문제점 1. 여러개의 인스턴스 생성
Multi-thread 환경에서 instance가 없을 때 동시에 아래의 getInstance() 메소드를 실행하는경우
각각 새로운 instance를 생성할 수 있습니다.
해결방안 1. synchonized 메소드선언
public class Singleton{
// 1개만 존재해야 하는 객체이므로 static으로 선언
private static Singleton instance;
//private 생성자로 외부에서 객체 생성을 막아야함.
private Singlngton(){
}
// 외부에서는 getInstance()로 instance 반환
public static synchronized Singleton geInstance(){
//instance가 null일때만 생성
if(instande == null){
instance = new Singleton();
}
return instance;
}
}
synchronized 키워드를 사용하여 getInstance() 메소드를 동기화 해주면,
최초로 접근한 쓰레드가 해당 메소드 호출을 종료할 때까지 다른 쓰레드가 접근하지 못하도록 Lock을 걸어둔다.
여러개의 쓰데르가 동시 접근하면서 생길 수 있는 문제를 방지 할 수있다는 장점이 있지만,
getInstance() 메소드를 호출할 때마다 Lock이 걸려 성능 저하가 발생한다는 문제가 있다.
그러므로 오버헤드가 굉장히 크다는 단점으로 권장하지 않는 방법이다.
여러가지 문제점들이 많지만 길어지니 따로 모아서 남기도록 하겠다.
결론
싱글톤 패턴은 메모리, 속도, 데이터 공유 측면에서 이점을 가지고 있다.
하지만, 싱글톤 패턴이 무조건 좋은것은 아니다. 위에 얘기했듯이 multi-thread 환경에서는
동시성 문제가 발생할 수 있기에 싱글톤 패턴을 사용하고자 한다면 사용하기 앞서
"해당 객체의 인스턴스가 한개만 존재해야 하는가?"의 여부와
"사용을 하였을때의 동시성 문제가 발생하지 않는지"를 체크를 하며 사용해야 할 것 같습니다"
'Java' 카테고리의 다른 글
Java 상속(inheritance) (0) | 2024.01.24 |
---|---|
형변환(캐스팅,casting)이란? (0) | 2024.01.19 |
JVM(Java Virtual Machine) 이란? (0) | 2024.01.17 |
자바 특징 정리 (0) | 2024.01.17 |
[Java] 트랜잭션(transaction)에 대해서 (0) | 2024.01.16 |