공부/Java

동시성 문제와 TreadLocal

kkkkkdddddhhhhh 2024. 1. 4. 18:13

Spring 동시성 문제에 관한 강의를 듣고 

 

복습 겸 정리겸 겸사겸사..

 

우선 동시성 문제란...

n개의 Thread가 동시에 하나의 자원에 접근할 때 발생하는 문제

 

강의에서 본 학습 테스트로 직접 동시성문제를 겪어봤다.

 

 

nameStrore 라는 이름을 저장하는 필드값이 존재하고

fieldService가 제공하는 logic이라는 메서드에서는 매개변수로 name을 받고 

log로 받은 name, nameStore에 현재 어떤 name값이 들어와있는지를 조회한다. 

 

(동시성문제 확인을위해 nameStore 조회전 1초간 Thread를 멈췄다.)

 

 

테스트는 2개의 Thread로 name을 nameStore에 저장해본다. 

 

첫번째 동시적으로 nameStore Field 변수에 접근하지않고 2초라는 시간텀을 두고 각각의 쓰레드가 천천히 접근했을때 결과는..

userA의 name이 저장된 뒤 userA가 조회됬고, 2초후

userB의 name이 저장되고 userB가 조회되는 정상 동작이 처리됨

 

 

두번째 테스트는 동시성 문제를 확인하기위해 2초의 시간차를 두지않고 0.1초만에 바로 TreadB로 동시에 요청을 진행했다. 결과는..

userA의 name이 nameStore에 저장되고 조회가 되기전 바로 userB의 name 저장 요청이 들어와 

 

userA의 nameStore 조회시 userB가 조회되는 동시성 문제가 발생했다.

 

Java에서는 이러한 동시성 문제의 해결을 위해 ThreadLocal을 지원한다.

 

쓰레드 로컬이란 쓰레드A,B가 있을때 쓰레드A의 보관소를 만들어 쓰레드A의 요청값을 따로 보관해 동시에 쓰레드B의 요청이 들어와도 

쓰레드A의 조회결과는 쓰레드A의 보관소에 저장한 값을 조회하기에 동시성문제를 해결 할 수 있다.

 

학습 테스트를 통해 직접 확인해보자.

 

 

필드값이 단순 String에서 ThreadLocal<>로 변경됬다.

 

 

ThreadLocal은 내부적으로 ThreadLocalMap을 가져 이 Map의 Thread data를 저장한다.

 

ThreadLocal을 사용할때에는 set을 통해 값을 넣어주고 get을 통해 값을 가져오자.

 

 

테스트를 통해 ThreadA,B가 동시에 같은 리소스에 요청을 했을때 

단순 필드변수와 달리 정상적으로 저장과 조회가 처리되는것을 확인 할 수 있었다. 개꿀

 

마지막으로 ThreadLocal 사용시 주의점

 

 

스프링과 같이 쓰레드풀을 사용하는 경우 ThreadLocal 사용을 마치면 해당 보관소의 값들을 지워줘야한다. 

만약 지우지않을 경우 

UserA의 데이터 저장 요청으로 ThreadPool에서 ThreadA가 ThreadLocal에 값을 보관한다. 요청이 완료되고 -> remove() 생략시

UserB의 데이터 조회 요청으로 ThreadPool에  그 전 요청을 마무리하고 대기하던 ThreadA가 랜덤하게 선택되고 ThreadA의 ThreadLocal 보관소 값을 조회하게 된다.

 

remove() 생략시 UserB가 UserA의 데이터를 조회하게 되는 문제가 발생.

 

이 점을 유의해 ThreadLocal을 사용하는 로직이 마무리되면 remove()를 이용해 보관소의 값을 필수로 지워줘야한다.

'공부 > Java' 카테고리의 다른 글

Decorator Pattern  (0) 2024.01.09
Proxy Pattern  (0) 2024.01.08
TemplateMethod Pattern | Strategy Pattern  (0) 2024.01.06