쓰레드 로컬은 해당 쓰레드만 접근할 수 있는 특별한 저장소를 말한다.
(같은 인스턴스의 쓰레드 로컬 필드에 접근해도 문제가 없음)
- 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();
}
}
}
- 동시성 문제가 발생하지 않는 코드 작성
@Slf4j
public class ThreadLocalServiceTest {
private ThreadLocalService fieldService = new ThreadLocalService();
@Test
void field() {
log.info("main start");
Runnable userA = () -> fieldService.logic("userA");
Runnable userB = () -> fieldService.logic("userB");
Thread threadA = new Thread(userA);
threadA.setName("thread-A");
Thread threadB = new Thread(userB);
threadB.setName("thread-B");
threadA.start();
sleep(2000);
threadB.start();
sleep(3000);
log.info("main exit");
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//01:00:39.413 [Test worker] INFO hello.advanced.threadlocal.ThreadLocalServiceTest - main start
//01:00:39.419 [thread-A] INFO hello.advanced.threadlocal.code.ThreadLocalService - 저장 name=userA -> nameStore=null
//01:00:40.439 [thread-A] INFO hello.advanced.threadlocal.code.ThreadLocalService - 조회 nameStore=userA
//01:00:41.424 [thread-B] INFO hello.advanced.threadlocal.code.ThreadLocalService - 저장 name=userB -> nameStore=null
//01:00:42.431 [thread-B] INFO hello.advanced.threadlocal.code.ThreadLocalService - 조회 nameStore=userB
//01:00:44.435 [Test worker] INFO hello.advanced.threadlocal.ThreadLocalServiceTest - main exit
}
- userA요청이 들어옴 nameStore에 userA저장
- userB요청이 들어옴 nameStore에 null인 상태를 볼수 있음(기존 이전글에서는 userA가 저장되어있었음)
- 동시성 발생하게 코드 작성
@Test
void field() {
log.info("main start");
Runnable userA = () -> fieldService.logic("userA");
Runnable userB = () -> fieldService.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(3000);
log.info("main exit");
//01:03:57.595 [thread-A] INFO hello.advanced.threadlocal.code.ThreadLocalService - 저장 name=userA -> nameStore=null
//01:03:57.711 [thread-B] INFO hello.advanced.threadlocal.code.ThreadLocalService - 저장 name=userB -> nameStore=null
//01:03:58.616 [thread-A] INFO hello.advanced.threadlocal.code.ThreadLocalService - 조회 nameStore=userA
//01:03:58.722 [thread-B] INFO hello.advanced.threadlocal.code.ThreadLocalService - 조회 nameStore=userB
}
- userA요청이 들어오고 nameStore에 userA저장중
- userA요청이 끝나기전에 userB요청이 들어왔지만, ThreadLocal로 인해 서로의 값에 영향을 주지 않음
'SPRING > 스프링' 카테고리의 다른 글
[스프링 핵심 원리-고급] 템플릿 콜백 패턴 (0) | 2022.01.27 |
---|---|
[스프링 핵심 원리 -고급] 전략패턴 (0) | 2022.01.27 |
[스프링 핵심 원리-고급] 템플릿 메서드 패턴 (0) | 2022.01.25 |
[스프링 핵심 원리-고급] 쓰레드 로컬 주의사항 (0) | 2022.01.22 |
[스프링 핵심 원리-고급]필드 동기화 -동시성 문제 (0) | 2022.01.21 |