티스토리 뷰

반응형

스프링 빈(bean)은 쓰레드 세이프.. 하겠..지??

빈(bean)은 개발자 입장에서 편리합니다. 스프링이 생성하고 관리하고 조립도 해주고 많은 제어를 많이 해주니까 말이죠. (어제까지만 해도) 저는 스프링 빈(bean)이라면 쓰레드 세이프 할 것이라는 무지에서 비롯된 믿음이 있었습니다. 하지만 스프링 빈(bean)은 근본적으로 쓰레드 세이프 하지 않습니다.

 

왜 쓰레드 세이프 하다고 오해했을까?

같이 공부하는 (주니어 개발자) 친구들에게 질문해봐도 이 부분에서 같은 오해를 하는 친구들이 많다는 걸 알 수 있었습니다. 왜 이런 오해를 하고 있을까요?

 

첫번째 이유는 많은 요청을 받는 멀티 쓰레드 환경에서 학습해보지 못한 경험상에 이유입니다.

 

두번째 이유는 (놀랍게도) 쓰레드 세이프하게 빈(bean) 클래스를 만들고 있었기 때문입니다. 멀티 쓰레드에 대한 지식이 없더라도 스프링 개발자들이 배우고 학습한 자료에는 쓰레드 세이프하게 만들어진 예제만 존재합니다. 알게 모르게 체득하게 된 것이죠.

 

그러면 쓰레드 세이프 하지 못한 빈(bean) 클래스는 어떤 경우지?

값이 변할 수 있는 인스턴스 멤버 변수가 존재한다면 쓰레드 세이프 하지 않습니다. (좀 더 유식하게 말하지만 이런 경우 '상태를 가지고 있다' 라고 합니다. 그래서 '무상태(stateless)'인 빈(bean) 클래스를 만들어야 합니다. 그리고 이 사실은 빈 뿐만아니라 모든 객체에 해당하는 얘기입니다.)

class MyBean{
    String name; //멀티 쓰레드 환경에서 문제 발생의 원흉!!

    public void setName(String name){ 
        this.name = name; //이름이 바뀐다면 다른 쓰레드에도 영향을 받게 된다.
        ...
    }
}

위와 같이 name이라는 인스턴스 변수가 존재하는데 setName() 메소드를 이용하면 변수 값이 바뀌게 됩니다. 하지만 바뀐 값이 다른 쓰레드 입장에서는 예상치 못한 변화로 문제를 일으킬 수 있습니다.

 

해결 방법(2가지)

1. 각 요청에 맞는 변수 값이 필요하다면, 인스턴스 멤버 변수로 선언하지 말고 지역 변수로써 사용한다.

class MyBean{
    public void setName(String name){ 
        name ... //지역 변수로써 사용하게 되면 영향이 없다.
    }
}

2. (지역 변수로써 사용하고 싶지 않다면) scope 옵션을 prototype으로 한다.

기본적인 scope 설정은 singleton이기 때문에, 새로운 요청이 들어와도 하나의 빈(bean)객체가 처리를 하게 됩니다. 이런 경우 scope 설정을 prototype으로 둔다면 매 요청시마다 새로운 객체가 생성되어 처리 되게 됩니다.

하지만 매 요청시마다 객체가 새로 생성된다는 것은 성능상의 많은 단점을 내포하고 있으니 가능한 최후의 수단(?)으로 고려해봅니다.

 

두줄 요약

  1. 스프링 빈(bean)은 쓰레드 세이프 하지 않다.
  2. 스프링 빈(bean) 클래스에 인스턴스 변수 멤버가 있지 않은지 확인해보자. 만약 존재한다면 읽기 전용인 경우만 허용한다. 값이 변하게 되는 변수인 경우는 지역 변수로 넣어버리자.

참고자료

반응형
댓글