[Java] 스레드 로컬 - Thread Local
스레드 로컬이란
여러개의 스레드가 존재할 때, 해당 스레드만 접근할 수 있는 특별한 저장소를 말한다.
스레드 로컬 클래스는 한 스레드에 의해 읽고 쓰여지는 변수를 생성한다.
각 스레드마다 별도의 내부 저장소가 제공된다.
스레드 로컬을 사용하는 이유 , 동시성 문제
서로 다른 두 스레드가 하나의 변수에 접근해 동시에 값을 변경한다면 이 변수는 공유 자원으로 동시성 문제가 발생할 수 있다.
동시성 문제는 트래픽이 적은 상황에서는 괜찮은데 트래픽이 많아질수록 자주 발생한다.
또한 스프링 빈처럼 싱글톤 객체의 필드를 변경하며 사용할 때도 동시성 문제에 대해 조심해야 한다.
이러한 문제를 해결하기 위해 스레드 로컬을 사용한다.
스레드 로컬 사용 시 주의사항
스레드 로컬을 모두 사용하고나면 remove 메서드를 호출해 스레드 로컬에 저장된 값을 제거해야한다.
스레드를 생성하는 비용은 비싸기 때문에 스레드 사용 시 보통 재사용되는데 데이터를 삭제하지 않으면 스레드 로컬의 데이터는 계속 남아있기 때문이다.
WAS 처럼 스레드 풀을 사용하는 경우, 스레드 로컬에 저장된 데이터를 스레드 풀에 반환하고
이후 스레드 풀에서 동일한 스레드를 꺼내서 사용하면
이전에 저장한 스레드 로컬의 데이터가 반환되어서 치명적인 버그가 발생할 수 있다.
쉽게말해 userB가 userA의 데이터를 사용할 수 있게 되는 것이다.
Thread Local 를 사용하는 SecurityContextHolder
SecurityContextHolder 은 싱글톤 객체로 Thread Local 을 사용한다
SecurityContextHolder는 단순히 유저 인증 정보를 담고 있는 객체로 Thread Local 관련 기능은 지원하지 않는다.
SecurityContextHolder.getContext().getAuthentication() 이런식으로 컨텍스트홀더에서 컨텍스트를 가지고 오거나 지울 때,
InheritableThreadLocalSecurityContextHolderStrategy 보시면 스레드 로컬로 구현이 되어있는것을 확인할 수 있다.
private static final ThreadLocal<Supplier<SecurityContext>> contextHolder = new InheritableThreadLocal<>();
@Override
public void clearContext() {
contextHolder.remove();
}
참고