Spring Boot 동시성 문제 - ThreadLocal

1

SpringBoot

목록 보기
2/3

동시성 문제

일반적으로 두개 이상의 세션에서 공통된 데이터에 접근하여 읽거나 쓰는 작업이 이루어질 경우 발생 할 수 있는 문제


위와 같은 프로세스가 있다고 가정했을때 두개의 쓰레드가 같은 자원을 두고 읽고 쓰는 작업을 하고있다.
그러므로 더 늦게 시작한 Thread-B에 의해 Thread-A의 데이터가 무시되는 현상이 일어나게 된다. 이를 “손실되는 업데이트” 라고 한다.

  • Thread-A : "userA" 저장

  • Thread-B : "userB" 저장 -> "userA" 정보 사라짐

private String nameStore;

public String logic(String name){
        log.info("저장 name={} --> nameStore={}", name, nameStore);
        String localField = name;
        nameStore = name;
        sleep(1000);
        log.info("조회 nameStore={}, localField={}", nameStore, localField);
        return nameStore;
    }

위와 같은 메소드가 있을때

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");

테스트 코드로 결과를 확인해 보면

nameStore 필드값이 나중에 셋팅된 Thread-B 값에 의해 꼬이게 된다.

ThreadLocal

해당 쓰레드만 접근할수있는 특별한 저장소이다.
물건 저장 창고를 떠올려보면, 창구직원이 사용자에 따라서 보관한 데이터를 구분해서 꺼내주기 때문에 제대로 된 데이터가 보장될 수 있다.

ThreadLocal은 각 쓰레드마다 별도의 내부 저장소를 제공한다.


데이터를 동시에 쓰게 되어도 ThreadLocal이 보관소를 구분해서 저장해줌

  • Thread-A : "userA" 저장 -> ThreadLocal Thread-A 전용 보관소에 저장해줌

  • Thread-B : "userB" 저장 -> ThreadLocal Thread-B 전용 보관소에 저장해줌

private ThreadLocal<String > nameStore = new ThreadLocal<>();

public String logic(String name){
        log.info("저장 name={} --> nameStore={}", name, nameStore.get());
        String localField = name;
        nameStore.set(name); // 저장
        sleep(1000);
        log.info("조회 nameStore={}, localField={}", nameStore.get(), localField);
        return nameStore.get(); // 저장한 데이터 꺼내기
        // 값 제거 : nameStore.remove() - 해당 쓰레드가 쓰레드 로컬을 모두 사용하고 나면 ThreadLocal.remove() 로 로컬에 저장된 값을 제거해 주어야 함
    }

ThreadLocal을 사용하여 메소드를 수정 후 다시 테스트 코드를 실행 해보면

본인의 Thread에 저장한 값이 알맞게 출력된다.

출처 : 인프런-스프링 핵심원리 고급편 강의

0개의 댓글