본문 바로가기
Spring/Spring-detail

JAVA 싱글톤, Spring 싱글톤에 대해.

by YoonJong 2023. 3. 23.
728x90

스프링이나 디자인 패턴을 공부하면 싱글톤 패턴을 학습하고 어떤 의미인지 인지하고 있다고 생각합니다.

 

싱글톤은 인스턴스를 오직 한개만 제공하는 클래스입니다.

먼저, 몇가지 싱글톤을 구현하는 방법에 대해 알아보고 사용하는 이유와 주의해야할 점에 대해 알아보겠습니다.


JAVA 싱글톤 생성방법

첫 번째 방법입니다.

가장 간단하게 생성할 수 있으며, 보편적으로 사용하는 형태입니다.

static 을 통해 생성한 Singleton 은 클래스가 로드 될때 객체를 생성해 사용합니다.

해당 방법은 객체를 사용하지 않더라도 무조건 생성되기 때문에, 자원의 낭비가 발생합니다.

또한, 객체 생성시에 예외처리가 불가능합니다.

public class Singleton {
    // static 을 통해 class 로드될때 객체를 생성
    private static Singleton instance = new Singleton();

    // 외부에서 인스턴스를 생성하지 못하도록 private 사용
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
}

public static void main(String[] args) {
    Singleton singleton = new Singleton(); // 사용불가
}

 

두 번째 방법입니다.

아래 방법은 getInstance() 메서드를 호출해야 instance 가 생성됩니다.

또한 instance 가 존재할 때는, 추가로 생성하지 않고 이미 존재하는 instance를 반환하게 됩니다.

자원의 비효율성은 보완할 수 있지만, 멀티 스레드 환경에서 동기화 문제가 발생할 수 있습니다.

 

동시에 여러 곳에서 getInstance() 를 호출하면 새로운 instance 가 생성되기 때문입니다.

따라서, 싱글스레드 환경에서는 안전하지만 멀티스레드 환경에서는 문제가 될 수 있습니다.

public class Singleton {
    // static 을 통해 class 로드될때 객체를 생성
    private static Singleton instance;

    // 외부에서 인스턴스를 생성하지 못하도록 private 사용
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

 

위의 문제인 동기화 문제를 해결하기 위해서는 아래와 방법을 고려해 볼 수 있습니다.

Synchronized 키워드를 사용하면 하나의 스레드만 실행하는 것을 보장합니다. 

(동시에 접근하고 공유되는 자원에서 문제가 발생하지 않도록 보장해줘야 하는 임계영역)

해당 코드의 문제점은 비용 문제가 발생할 수 있습니다.

객체 하나를 안전하게 생성하기 위해 Synchronized 를 사용하는데, 해당 Singleton 객체를 자주 사용하게 되면,

호출 할때 많은 비용이 발생할 수 있습니다.

public class Singleton {

    private static Singleton singleton;

    private Singleton() {} 
    
    public static synchronized Singleton getInstance() {
        if (singleton == null) singleton = new Singleton();
        return singleton;
    }
}

JAVA 싱글톤을 사용하는 이유

먼저 생각나는 이유 중 하나는 하나의 객체만 생성하기 때문에 메모리 관점에서 이점을 얻을 수 있다는 것입니다.

하나의 인스턴스를 생성(new) 해서 고정된 메모리 영역에서 가져와 재활용하기 때문입니다.

 

미리 메모리에 생성해두기 때문에, 다시 불러와 사용할 경우 속도적인 측면에서도 성능 향상이 있습니다.

 

추가적인 이점으로는 데이터의 공유입니다.

다른 클래스에서도 필요에 따라, 하나의 객체를 불러와 사용할 수 있기 때문입니다.

하지만, 동시성의 문제가 발생할 수 있다는 점을 유의해야 합니다.


JAVA 싱글톤의 문제점 

싱글톤은 메모리 관련한 이점을 가지고 있지만, 다양한 문제를 발생시킬 수 있는 원인이 되기도 합니다.

 

가장 크리티컬한 원인은 메모리 누수의 원인이 될 수 있다는 것입니다.

static 으로 생성한 싱글톤 객체는 GC(가비지컬렉터) 에 의해 제거 되지 않습니다.

오직 프로그램을 종료해야 반환되기 때문에,  무분별한 생성은 지양해야 합니다.

 

동시성의 문제가 발생할 수 있습니다.

멀티스레드 환경에서 getInstance() 를 동시에 호출하게 되면 인스턴스가 n개 생성될 수 있습니다.

이러한 점을 보완하기 위해서 Syncronized 를 사용하게 되는데, 이 또한 자주 호출할 경우 비용이 많이 발생하게 됩니다.

 

테스트를 작성하기 불편합니다.

싱글톤은 생성 방식이 제한적이기 때문에 MOCK 객체로 대채하기 어렵습니다.

개발에서는 테스트 작성이 불가피하기 때문에, 큰 단점이 될 수 있습니다.

 

싱글톤을 단독적으로 사용하게 되면 많은 단점으로 인해 안티패턴 이라고 불리기도 합니다.

이를 보완하기 위해서는 프레임워크의 도움 (위임) 을 통해 문제점을 해결할 수 있습니다.


스프링 싱글톤

스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 인스턴스를 싱글톤으로 관리합니다.

스프링 프레임워크를 통해 직접 객체(bean) 들을 싱글톤으로 관리해 클래스에 불필요한 코드를 제거하고,

객체를 재사용할 수 있습니다.

 

특정 클래스에 대해 @Bean 이 정의되면, 스프링 컨테이너는 해당 클래스에 대해 단 하나의 인스턴스를 생성합니다.

bean 이 호출될 때마다 스프링은 생성된 공유 인스턴스를 반환합니다.

 

단 하나의 공유 인스턴스를 리턴시키기 때문에 멀티스레드에 대한 동시성 문제도 해결할 수 있습니다.

(Thread safety를 자동으로 보장)

 

 

https://javabeat.net/spring-singleton-java-singleton/

 

Difference Between Java Singleton and Spring Singleton

This blog post explains the key difference between Java Singleton and Spring Singleton with simple example programs

javabeat.net

 

728x90

댓글