동시성 문제는 지역 변수에서는 발생하지 않는다.
지역 변수는 쓰레드마다 각각 다른 메모리 영역이 할당된다. > 동시성 문제가 발생하는 곳은 같은 인스턴스의 필드(주로 싱글톤에서 자주 발생), 또는 static 같은 공용 필드에 접근할 때 발생한다. > 동시성 문제는 값을 읽기만 하면 발생하지 않는다. 어디선가 값을 변경하기 때문에 발생한다.
이럴 때 사용하는 것이 바로 쓰레드 로컬이다
ThreadLocal 예제 소스
@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 (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadLocal 사용
값 저장: ThreadLocal.set(xxx)
값 조회: ThreadLocal.get()
값 제거: ThreadLocal.remove()
ThreadLocal을 모두 사용하고 나면 반드시 값제거를 해야 한다!!
ThreadLocalServiceTest
@Slf4j
public class ThreadLocalServiceTest {
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-A");
Thread threadB = new Thread(userB);
threadB.setName("thread-B");
threadA.start();
sleep(100);
threadB.start();
sleep(2000);
log.info("main exit");
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
실행 결과
[Test worker] main start
[Thread-A] 저장 name=userA -> nameStore=null
[Thread-B] 저장 name=userB -> nameStore=null
[Thread-A] 조회 nameStore=userA
[Thread-B] 조회 nameStore=userB
[Test worker] main exit
쓰레드 로컬로 하면 쓰레드 마다 별도의 데이터 저장소를 가지게 되어 동시성 문제 해결이 가능하다
'프레임워크 > 스프링' 카테고리의 다른 글
[Spring] 프록시, 프록시 패턴, 데코레이터 패턴 (0) | 2022.11.12 |
---|---|
[Spring] 템플릿 콜백 패턴 (1) | 2022.11.11 |
[Spring] 로그 추적기 파라미터로 동기화 개발 (0) | 2022.11.01 |
[Spring] 로그 추적기 프로토타입 개발 (0) | 2022.10.31 |
@Resource vs @Autowired vs @Inject (0) | 2022.10.27 |