[Spring boot] 싱글톤 패턴의 쓰래드 문제

2021. 6. 5. 15:14프로그래밍/web

싱글톤 패턴은 spring에서 기본적으로 사용되는 패턴으로

<위키백과>
소프트웨어 디자인 패턴에서 싱글턴 패턴을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다

이런 특성을 가지고 있다.

싱글톤 패턴의 장점은 컨테이너가 서비스 객체를 생성하고 지우는 부담을 줄여주어, 메모리 관리에서 강점을 가진다.

하지만, 쓰래드 문제도 존재해 stateless 한 상태로 만드는 것이 필수적이다.

말로는 감이 잘 안올테니 코드를 통해 확인해보자

 

StatefulService.java

public class StatefulService {
    // 얘가 문제를 만듦. 무상태로 만들어야함.
    private int price;

    public void order(String name, int price){
        System.out.println(name+"price = "+price);
        this.price = price;
    }
    public int getPrice(){
    	return this.price;
    }
 }

StatefulServiceTest.java

public class StatefulServiceTest {
    public void statefulTest(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(StatefulService.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);
		
        
	statefulService1.order("A", 2000);
        statefulService2.order("B", 1000);

        System.out.println(statefulService1.getPrice()); 		
        System.out.println(statefulService2.getPrice());
    }
}

위 코드를 실행시키면 값은 놀랍게도 1000, 1000이 나온다.

그 이유는 현재 statefulService는 공유되고 있고, statefulService1과 statefulService2는 같은 StatefulService 객체를 사용하고 

있기 때문이다.

 

이 문제 해결을 위해서는 Service의 state를 stateless하게 만들어 주어야 한다.

StatefulService.java

public class StatefulService {
    // 얘가 문제를 만듦. 무상태로 만들어야함.
//    private int price;

    public int order(String name, int price){
        System.out.println(name+"price = "+price);
//      this.price = price;
        return price;
    }
}

StatefulServiceTest.java

    public void statefulTest() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(StatefulService.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        int userAprice = statefulService1.order("A", 2000);
        int userBprice = statefulService2.order("B", 1000);

        System.out.println(userAprice);
        System.out.println(userBprice);
       	}
    }

이렇게 price라는 상태를 order라는 함수 안의 지역변수로 만들어 줌으로써 문제를 간단하게 해결할 수 있었다.