스프링 핵심 원리(고급편)

Ch02. 쓰레드 로컬(ThreadLocal) - ThreadLocal

webmaster 2022. 4. 8. 11:34
728x90
  • 스레드 로컬은 해당 스레드만 접근할 수 있는 특별한 저장소를 말한다
  • 쉽게 이야기해서 물건 보관 창구를 떠올리면 된다. 여러 사람이 같은 물건 보관 창구를 사용하더라도 창구 직원은 사용자를 인식해서 사용자별로 확실하게 물건을 구분해준다.
  • 사용자 A, 사용자 B 모두 창구 직원을 통해서 물건을 보관하고, 꺼내지만 창구 지원이 사용자에 따라 보관한 물건을 구분해주는 것이다

일반적인 변수 필드

일반 변수 필드 접근 ThreadA
일반 변수 필드 접근 ThreadB

스레드 로컬

쓰레드 로컬 변수 변경 threadA
쓰레드 로컬 변수 변경 threadB
동시에 접근해도 본인의 전용 보관소에서 꺼내기 떄문에 동시성 문제 X

  • 자바는 언어 차원에서 스레드 로컬을 지원하기 위한 java.lang.ThreadLocal 클래스를 제공한다.

예제 코드

ThreadLocalService

@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();
        }
    }
}

ThreadLocalServiceTest

@Slf4j
public class ThreadLocalServiceTest {

    private ThreadLocalService fieldService = new ThreadLocalService();

    @Test
    public 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); //동시성 문제 발생 X
        sleep(100);//동시성 문제 발생
        threadB.start();

        sleep(3000);//메인 쓰레드 종료 대기
        log.info("main exit");
    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

  • 해당 쓰레드가 스레드 로컬 값을 다 사용하면 반드시 threadlocal.remove()를 호출해서 스레드 로컬에 저장된 값을 제거해 주어야 한다.
  • 각각의 별도 데이터 저장소를 가지면서 동시성 문제가 해결되었다.
728x90