1 분 소요


Concurrency Issue

동시성 문제란 동일한 자원에 대해서 여러 스레드가 동시에 접근해서 값을 바꾸면서 발생하는 문제를 뜻한다. 단순히 읽기를 할때는 문제가 발생하지 않지만 값을 바꾸게 되면 문제가 발생할 수 있다.


예시를 보고 이해해보자.

img1

위 그림에서의 FieldService는 Spring bean으로 등록되어 있어서 싱글톤으로 관리되는 상태이다. 그런데 Thread-A 가 FieldService의 맴버 변수 nameStore에 접근해서 값을 바꾼 후 조회하는 로직을 실행하였다. 이 로직을 실행하고 있는 시점에 동시에 Thread-B가 동일한 로직을 실행했다고 생각해보자. 그러면 Thread-A가 값을 조회하기 전에 Thread-B가 값을 바꾸면 Thread-A에서 조회한 값이 Thread-B가 바꾼 값으로 조회될 수 있다. 원래 기대한 결과와는 다른 결과가 도출된 것이다. 이런 문제를 동시성 문제라고 한다.

그렇다면 이러한 문제를 어떻게 해결할 수 있을까? Java에서 제공하는 ThreadLocal을 사용하면 된다 ^-^

ThreadLocal

TheadLocal은 해당하는 Thread만 접근할 수 있는 특별한 저장소라고 생각하면 된다. 다른 Thread에서 접근할 수 없다. 그림을 보고 이해해보자.

img2

Thread-A가 ThreadLocal에 값을 넣으면 ThreadLocal은 Thread-A의 전용 저장소에 값을 저장한다. 그러면 다른 Thread에서는 이 저장소에 접근해서 값을 읽거나 쓸 수 없다. 오직 Thread-A만 접근할 수 있는 것이다.

사용 방법 및 주의점

ThreadLocal에서 값을 넣을땐 set()을 사용하고 꺼낼때는 get()을 사용하면 된다.
한 가지 주의점이 있는데 ThreadLocal을 다 사용하고 나면 반드시 ThreadLocal.remove()를 호출해서 ThreadLocal에 저장된 값을 지워줘야 한다.
이유는 그림을 통해서 설명하겠다.

img3

Tomcat 같은 WAS는 일반적으로 Thread pool 방식을 사용한다. Thread를 생성하는 비용이 비싸기 때문에 미리 Thread들을 생성해두고 요청이 오면 해당 쓰레드를 할당해주는 방식이다. 그리고 요청이 끝나면 해당 Thread를 Thread pool에 반납한다. 때문에 Thread는 애플리케이션이 종료될 때까지 사라지지 않는다.
이런 상황속에서 사용자A가 HTTP 요청을 했다고 가정해보자. 요청에 대해서 WAS가 Thread pool에서 놀고 있는 Thread-A를 할당해줬다고 가정하자. 그리고 이 Thread-A에서 ThreadLocal에 값을 저장했다고 해보자. 그러면 사용자A 요청에 의한 어떤 값이 Thread-A 전용 저장소에 저장될 것이다. 그리고 요청이 끝나서 나갔다.

이제 다른 사용자B 가 HTTP 요청을 했다. 그런데 하필이면 WAS가 또 Thread pool에 있는 Thread-A를 할당했다고 해보자. 이렇게 되면 사용자A 와 전혀 관련없는 사용자B가 ThreadLocal을 통해 Thread-A 저장소에 저장된 사용자A의 정보를 확인할 수 있게 된다. 나와 전혀 상관없는 제3자가 내 정보를 조회하는 것이다. 이런 문제를 방지하기 위해서 반드시 ThreadLocal을 다 사용하고 나면 ThreadLocal에 저장된 값을 날려줘야 한다.

참고 사이트 출처

  • https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B3%A0%EA%B8%89%ED%8E%B8


더 자세한 내용은 김영한님 강의를 참고하자!