Java 싱글톤(Singleton) 패턴 : 객체를 하나만 생성하고, 그 객체를 어디서든 접근할 수 있도록 하는 디자인 패턴입니다. 이 패턴은 특정 클래스의 인스턴스가 하나만 생성되도록 보장하며, 이 인스턴스에 대한 전역적인 접근점을 제공합니다.
- 싱글턴 패턴을 사용하지 않으면:
- 매번 새 인스턴스가 생성됩니다.
- 클래스의 생성자가 매번 호출되어 새로운 객체가 생성됩니다.
public class MyClass {
public MyClass() {
System.out.println("MyClass constructor called!");
}
public void doSomething() {
System.out.println("Doing something...");
}
}
public class SingletonTest {
public static void main(String[] args) {
MyClass obj1 = new MyClass(); // 첫 번째 인스턴스 생성
obj1.doSomething();
MyClass obj2 = new MyClass(); // 두 번째 인스턴스 생성
obj2.doSomething();
}
}
- 출력결과 :
MyClass constructor called! //생성자 1회 호출
Doing something...
MyClass constructor called! //생성자 2회 호출
Doing something...
- 싱글톤 패턴의 주요 특징 :
- 유일한 인스턴스: 클래스의 인스턴스가 하나만 존재하도록 보장합니다.
- 전역 접근: 애플리케이션 어디에서든지 이 인스턴스에 접근할 수 있도록 합니다.
- 인스턴스 제어: 인스턴스 생성이 제한되므로 불필요한 리소스 사용을 방지할 수 있습니다.
- 싱글톤 예제 1번 : Double-Checked Locking 방식 성능 최적화를 위해 흔히 사용하는 방법 중 하나는 Double-Checked Locking입니다. 이 방법에서는 인스턴스가 이미 생성된 후에는 동기화를 피하는 방식으로, 성능을 최적화할 수 있습니다.
public class Singleton {
private static volatile Singleton instance;
private final String name;
private final int age;
// private 생성자, 값을 초기화하는 역할
private Singleton(String name, int age) {
this.name = name;
this.age = age;
}
// getInstance 메서드는 인스턴스를 한 번만 초기화하고 이후에는 같은 인스턴스를 반환
public static Singleton getInstance(String name, int age) {
if (instance == null) { // 첫 번째 체크 (동기화 없이)
synchronized (Singleton.class) {
if (instance == null) { // 두 번째 체크 (동기화된 상태에서)
// 첫 번째 인스턴스 생성 시 name과 age를 설정
instance = new Singleton(name, age);
}
}
}
return instance;
}
// Getter 메서드
public String getName() {
return name;
}
public int getAge() {
return age;
}
// 이 메서드는 인스턴스의 값을 변경할 수 없게 만들어서 불변성 유지
public static void resetInstance(String name, int age) {
throw new UnsupportedOperationException("Singleton instance cannot be reset");
}
}
public class SingletonTest {
public static void main(String[] args) {
// 첫 번째 인스턴스 생성 (name과 age 값 설정)
Singleton singleton = Singleton.getInstance("John", 30);
System.out.println("Name: " + singleton.getName());
System.out.println("Age: " + singleton.getAge());
// 동일한 인스턴스를 반환, 다른 값으로 초기화 불가능
Singleton singleton2 = Singleton.getInstance("Jane", 25);
System.out.println("Name: " + singleton2.getName()); // 기존 값 출력 ("John")
System.out.println("Age: " + singleton2.getAge()); // 기존 값 출력 (30)
// resetInstance() 메서드를 호출하여 재설정 불가
// singleton.resetInstance("New Name", 40); // 실행 시 예외 발생
}
}
- 싱글턴 클래스 요소 :
- 단일 인스턴스 보장: getInstance 메서드는 항상 동일한 인스턴스를 반환합니다. instance가 null인 경우에만 새로운 인스턴스를 생성하고, 그 후에는 기존의 인스턴스를 반환합니다.
- 멀티스레드 안전성: synchronized 키워드를 사용하여 멀티스레드 환경에서 동기화를 처리하고, 두 번째 체크를 통해 불필요한 동기화 작업을 피하고 성능을 최적화합니다.
- 불변 객체: name과 age 값은 객체가 한 번 생성되면 변경할 수 없습니다. 이는 객체의 불변성을 보장하는 중요한 요소입니다.
- 싱글톤 예제 2번 :
- enum은 자바에서 기본적으로 Serializability, Thread-Safety, Instance Control을 보장해주기 때문에, 이를 활용하여 Singleton 패턴을 구현하면 추가적인 코드 없이 간단하게 안전한 싱글턴 객체를 생성할 수 있습니다. enum 사용한 싱글턴 패턴은 구현이 간단하면서도, 멀티스레드 환경과 직렬화 문제를 자연스럽게 해결하는 강력한 방법입니다. 따라서 enum을 이용한 싱글턴 구현은 가장 안전하고 바람직한 방식입니다.
enum Singleton {
UNIQUE_INSTANCE("John", 30); // name과 age 값을 전달
private final String name;
private final int age;
// 생성자
Singleton(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Singleton instance created!");
}
// 싱글턴 객체에서 사용할 메소드들
public void doSomething() {
System.out.println("Doing something...");
}
// 값들을 반환하는 메소드
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class SingletonTest {
public static void main(String[] args) {
Singleton single = Singleton.UNIQUE_INSTANCE;
single.doSomething(); // 첫 번째 호출
System.out.println("Name: " + single.getName() + ", Age: " + single.getAge());
Singleton single2 = Singleton.UNIQUE_INSTANCE;
single2.doSomething(); // 두 번째 호출
System.out.println("Name: " + single2.getName() + ", Age: " + single2.getAge());
}
}
- 출력결과 :
Singleton instance created! //생성자 1번만 호출
Doing something...
Name: John, Age: 30
Doing something...
Name: John, Age: 30
'Java' 카테고리의 다른 글
| Java ThreadPoolExecutor를 활용한 Custom스레드 풀 구현 (1) | 2025.03.08 |
|---|---|
| Java 스레드 실행 및 안전한 종료 방법 (2) | 2025.02.16 |
| JAVA Index 기반 문자열 변형 및 랜덤 셔플러 (2) | 2025.02.15 |
| 비트 연산 (2) | 2025.01.31 |
| Java 빌더 패턴 (Builder Pattern) (0) | 2025.01.29 |