오봉이와 함께하는 개발 블로그
스프링 핵심 원리 - 고급편_쓰레드 로컬(쓰레드 로컬 소개, 예제 코드) 본문
728x90
ThreadLocal - 소개
쓰레드 로컬은 해당 쓰레드만 접근할 수 있는 특별한 저장소다.
일반적인 변수 필드
thread-A
가userA
라는 값을 저장하고thread-B
가userB
라는 값을 저장하면userA
는 사라진다.
쓰레드 로컬
간단하게 그림으로 표현하면 아래와 같다.
자바는 언어차원에서 쓰레드 로컬을 지원하기 위한 java.lang.ThreadLocal
클래스를 제공한다.
ThreadLocal - 에제 코드
ThreadLocalService
package com.example.advanced.trace.threadlocal.code;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ThreadLocalService {
private ThreadLocal<String> nameStore = new ThreadLocal<>();
public String logic(String name) {
log.info("저장 name={} -> nameStore={}", name, nameStore.get());
nameStore.set(name);
sleep(1000);
log.info("조회 nameStore={}",nameStore.get());
return nameStore.get();
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (Exception e) {
e.printStackTrace();
}
}
}
기존에 있던 FieldService
와 거의 같은 코드인데, nameStore
필드가 일반 String
타입에서 ThreadLocal
을 사용하도록 변경되었다.
ThreadLocal 사용법
- 값 저장:
ThreadLocal.set(xxx)
- 값 조회:
ThreadLocal.get()
- 값 제거:
ThreadLocal.remove()
주의 사항으로 해당 쓰레드가 쓰레드 로컬을 사용하고 나면
ThreadLocal.remove()
를 호출하여 쓰레드 로컬에 저장된 값을 제거해야 한다.
ThreadLocalServiceTest
package com.example.advanced.trace.threadlocal;
import com.example.advanced.trace.threadlocal.code.ThreadLocalService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
@Slf4j
public class ThreadLocalServiceTest {
private ThreadLocalService threadLocalService = new ThreadLocalService();
@Test
void field() {
log.info("main start");
Runnable userA = () -> {
threadLocalService.logic("userA");
};
Runnable userB = () -> {
threadLocalService.logic("userB");
};
Thread threadA = new Thread(userA);
threadA.setName("thread-A");
Thread threadB = new Thread(userB);
threadB.setName("thread-B");
threadA.start(); //A실행
sleep(100);
threadB.start(); //B실행
sleep(2000); //메인 쓰레드 종료 대기 >> 마지막에 하지 않으면 그냥 field() 메서드가 종료되어 threadB 실행 결과가 나오지 않음
log.info("main exit");
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
실행 결과
[main] INFO com.example.advanced.trace.threadlocal.ThreadLocalServiceTest -- main start
[thread-A] INFO com.example.advanced.trace.threadlocal.code.ThreadLocalService -- 저장 name=userA -> nameStore=null
[thread-B] INFO com.example.advanced.trace.threadlocal.code.ThreadLocalService -- 저장 name=userB -> nameStore=null
[thread-A] INFO com.example.advanced.trace.threadlocal.code.ThreadLocalService -- 조회 nameStore=userA
[thread-B] INFO com.example.advanced.trace.threadlocal.code.ThreadLocalService -- 조회 nameStore=userB
[main] INFO com.example.advanced.trace.threadlocal.ThreadLocalServiceTest -- main exit
쓰레드 로컬을 사용하여 별도의 데이터 저장소를 가지게 되어 동시성 문제가 해결됐다.
출처: 김영한 지식공유자의 스프링 핵심 원리 고급편
728x90
'BE > Spring' 카테고리의 다른 글
스프링 핵심 원리 - 고급편_쓰레드 로컬(주의사항) (0) | 2024.03.17 |
---|---|
스프링 핵심 원리 - 고급편_쓰레드 로컬(쓰레드 로컬 동기화 개발, 적용) (1) | 2024.03.17 |
스프링 핵심 원리 - 고급편_쓰레드 로컬(동시성 문제 - 예제 코드) (0) | 2024.03.17 |
스프링 핵심 원리 - 고급편_쓰레드 로컬(필드 동기화 적용, 동시성 문제) (0) | 2024.03.17 |
스프링 핵심 원리 - 고급편_쓰레드 로컬(필드 동기화 - 개발) (0) | 2024.03.17 |
Comments