본문 바로가기
혼자 공부하는 것들/Spring

Spring에서 동시성 문제를 해결해보자! [+ThreadLocal]

by applepick 2022. 4. 19.
반응형

예를 들어 보드게임 중 할리갈리라는 게임이 있죠. 어떤 과일이든 합이 5개가 된다면 빠르게 종(인스턴스)을 치고(스레드) 해당 카드를 가져가는 게임입니다. 이 상황과 비슷하다고 느껴지지 않나요? 동시에 하나의 종을 여러 플레이어가 접근하는 게임입니다.

간단하게 이야기해보자면, 여러 스레드동시같은 인스턴스의 필드의 값을 변경하면서 발생하는 문제를 동시성 문제라고 합니다.

이러한 동시성 문제는 지역 변수에서 발생하지는 않습니다. 자바에서 지역변수는 스레드마다 각각 다른 메모리 영역을 할당하기 때문입니다. 또한, 값을 읽기만 했을 경우 동시성 문제가 발생하지는 않습니다. 다른 곳에서 값을 변경할 때 문제가 생깁니다. 이런 동시성 문제는 여러 쓰레드가 같은 인스턴스의 필드에 접근해야 하기 때문에 트래픽이 적은 상황에서는 확률상 잘 나타나지 않습니다. 트래픽이 점점 많아질 수 록 자주 발생합니다. 특히 스프링 빈 처럼 싱글톤 객체의 필드를 변경하며 사용할 때 이러한 동시성 문제를 조심해야 합니다.

이 문제를 해결할 수 있는 방법은 바로 ThreadLocal입니다.


ThreadLocal

ThreadLocal은 해당 Thread만 접근할 수 있는 저장소를 말합니다. 위에 할리갈리에 적용해보자면 최종적인 종은 하나지만, 각각 플레이어가 종을 하나씩 가지고 있어 최종 종을 연결하여 요청하는 형식입니다. 

 

ThreadLocal을 사용하면 각 Thread마다 별도의 내부 저장소를 제공합니다. 

Thread A가 userA라는 정보를 저장하게 되면 ThreadLocal은 Thread A 저장 보관소에 보관하게 됩니다.

마찬가지로 hread B가 userB라는 정보를 저장하게 되면 ThreadLocal은 Thread B 저장 보관소에 보관하게 됩니다.

ThreadLocal을 통해서 데이터를 조회할 경우에도 각각 저장한 데이터를 반환해줍니다.

자바에서 ThreadLocal을 지원해주기 위해서 

import java.lang.ThreadLocal;

을 제공해주고 있습니다. 

 

ThreadLocal 사용법

private ThreadLocal<String> a = new ThreadLocal<>();

a.set(String) -> 값 저장
a.get() -> 값 조회
a.remove() -> 값 삭제

주의해야 할 점은 해당 쓰레드가 쓰레드 로컬을 모두 사용하고 나면  ThreadLocal.remove()를 호출해서 쓰레드 로컬에 저장된 값을 삭제해줘야합니다. 삭제하지 않는다면 WAS(톰켓)처럼 쓰레드 풀을 사용하는 경우 심각한 문제가 발생됩니다. 톰켓에서 쓰레드를 생성하는 비용은 비싸기 때문에 쓰레드를 제거하지 않고, 보통 쓰레드 풀을 통해서 쓰레드를 재사용합니다. 만약 ThreadLocal A가 요청을 끝내고 ThreadLocal의 값을 지우지 않았다면 ThreadLocal B가 같은 쓰레드를 할당받아 A의 요청이 보여지는 난감한 상황이 생길 수 있습니다. 꼭  ThreadLocal를 사용한다면 remove()를 맨 마지막에 선언해줘야 합니다.

 

 

 

 

스프링 핵심 원리 - 고급편 - 인프런 | 강의

스프링의 핵심 원리와 고급 기술들을 깊이있게 학습하고, 스프링을 자신있게 사용할 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

스프림의 핵심원리 고급 편을 들으면서 공부한 것을 정리하고 있습니다.

반응형

댓글