728x90
✏️ 개요
- 동시성 문제
- 여러 쓰레드가 동시에 같은 인스턴스의 필드 값을 변경하면서 발생하는 문제를 동시성 문제라고 한다.
- 스프링 빈처럼 싱글톤 객체의 필드를 변경하여 사용할 때, 이러한 동시성 문제를 조심해야 한다.
- 동시성 문제는 지역 변수에서는 발생하지 않는다. 지역 변수는 쓰레드마다 각기 다른 메모리 영역이 할당된다.
- 동시성 문제가 발생하는 곳은 같은 인스턴스의 필드, 또는 static 같은 공용필드에 접근할 때 발생한다.
- ThreadLocal
- 해당 쓰레드만 접근할 수 있는 특별한 저장소를 말한다. 즉, 각 쓰레드마다 별도의 내부 저장소를 제공한다.
- 자바는 언어차원에서 쓰레드 로컬을 지원하기 위한 java.lang.ThreadLocal 클래스를 지원한다.
📌 사용법
- 값 저장: ThreadLocal.set(xxx)
- 값 조회: ThreadLocal.get()
- 값 제거: ThreadLocal.remove()
- 해당 쓰레드가 쓰레드 로컬을 모두 사용하고 나면, ThreadLocal.remove()를 호출해서 쓰레드 로컬에 저장된 값을 제거해주어야 한다.
private ThreadLocal<String> nameStore = new ThreadLocal<>();
public String logic(String name) {
log.info("저장 전 name={} -> nameStore={}", name, nameStore.get());
nameStore.set(name);
log.info("저장");
sleep(1000);
log.info("조회 nameStore={}", nameStore.get());
return nameStore.get();
}
private ThreadLocalService service = new ThreadLocalService();
@Test
void threadLocal() {
log.info("main start");
Runnable userA = () -> {
service.logic("userA");
};
Runnable userB = () -> {
service.logic("userB");
};
Thread threadA = new Thread(userA);
threadA.setName("thread-AAA");
Thread threadB = new Thread(userB);
threadB.setName("thread-BBB");
threadA.start();
sleep(100);
threadB.start();
sleep(2000);
log.info("main exit");
}
🗒️ 결과
14:17:44.723 [Test worker] INFO hello.advanced.trace.threadlocal.ThreadLocalServiceTest -- main start
14:17:44.726 [thread-AAA] INFO hello.advanced.trace.threadlocal.code.ThreadLocalService -- 저장 전 name=userA -> nameStore=null
14:17:44.727 [thread-AAA] INFO hello.advanced.trace.threadlocal.code.ThreadLocalService -- 저장
14:17:44.831 [thread-BBB] INFO hello.advanced.trace.threadlocal.code.ThreadLocalService -- 저장 전 name=userB -> nameStore=null
14:17:44.832 [thread-BBB] INFO hello.advanced.trace.threadlocal.code.ThreadLocalService -- 저장
14:17:45.732 [thread-AAA] INFO hello.advanced.trace.threadlocal.code.ThreadLocalService -- 조회 nameStore=userA
14:17:45.837 [thread-BBB] INFO hello.advanced.trace.threadlocal.code.ThreadLocalService -- 조회 nameStore=userB
14:17:46.836 [Test worker] INFO hello.advanced.trace.threadlocal.ThreadLocalServiceTest -- main exit
📌 ThreadLocal.remove()
- Tomcat과 같은 WAS는 Thread Pool을 사용한다.
- 따라서 ThreadLocal을 모두 사용하고 나면 ThreadLocal.remove()를 호출해서 ThreadLocal에 저장된 값을 제거해주어야 한다.
private void releaseTraceId() {
TraceId traceId = traceIdHolder.get();
if (traceId.isFirstLevel()) {
traceIdHolder.remove();
} else {
traceIdHolder.set(traceId.createPreviousId());
}
}
🔨 설정
@Configuration
public class LogTraceConfig {
@Bean
public LogTrace logTrace() {
return new ThreadLocalLogTrace();
}
}
참고
https://mangkyu.tistory.com/258
728x90
'Language > Java' 카테고리의 다른 글
자바에서 파일 업로드 검증 (0) | 2023.07.02 |
---|---|
자바에서 파일 다루기 (링크) (0) | 2023.06.27 |
Heap과 Priority Queue (0) | 2023.05.29 |
메모리 구조 및 특징 (0) | 2023.05.29 |
Comparable과 Comparator (0) | 2023.05.25 |