새소식

반응형
Java

[Java] ThreadLocal이란

  • -
반응형

ThreadLocal은 JDK 1.2부터 제공된 오래된 클래스입니다. 

ThreadLocal 클래스를 활용하면 스레드 단위로 로컬 변수를 사용할 수 있기 때문에 마치 전역 변수처럼 여러 메서드에서 활용할 수 있습니다.

 

ThreadLocal 클래스는 thread-local 변수들을 제공합니다. 

이 변수들은 각 스레드가 독립적으로 변수의 초기화 된 사본을 가지고 있습니다. 

ThreadLocal 인스턴스들은 보통 스레드와 상태를 연결하려고 하는 클래스들의 private static 필드들입니다.

(예를 들어, 유저 ID 또는 트랜잭션 ID)

 

set, get, remove - threadLocal의 로컬 변수 조작 

withInitial - static 메서드를 이용한 객체 생성

 

객체 공유 방안 ( 파라미터, 전역 변수..)

ThreadLocal은 하나의 Thread에서 실행되는 코드가 동일한 객체를 사용할 수 있도록 해 주기 때문에 

Thread와 관련된 코드에서 파라미터를 사용하지 않고 객체를 전파하기 위한 용도로 주로 사용됩니다. 

주요 용도는 다음과 같습니다.

 

사용자 인증정보 전파 - Spring Security에서는 ThreadLocal을 이용해서 사용자 인증 정보를 전파합니다.

트랜잭션 컨텍스트 전파 - TransactionManager는 TransactionContext를 전파하는 데 ThreadLocal을 사용합니다.

스레드에 안전해야 하는 데이터 보관

이 외에도 Thread 기준으로 동작해야 하는 기능을 구현할 때 ThreadLocal을 유용하게 사용할 수 있습니다.

 

SpringSecurity의 SecurityContextHolder

DispatcherServlet을 통해 요청이 들어오면, 요청을 받은 Thread별 인증 정보가 ThreadLocal에 보관되고,

Thread 내에서 계속 공유가 된다.

 

Thread를 생성하는 비용이 비싸기 때문에, Thread를 미리 만들어 pool을 생성해 재활용합니다.

ThreadLocal을 사용 시, 다 사용된 값은 비워주어야 다음에 Thread 동작에 오동작을 방지할 있습니다. 

 

public class ThreadLocalTest { // private static ThreadLocal<String> threadLocal = new ThreadLocal<>(); private static ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> "str"); private String threadLocal_str = ""; public void test_thread_local(String str) { threadLocal.set(str); ThreadLocalTest.sleep(1000); System.out.println("ThreadLocal Test : " + threadLocal.get()); threadLocal.remove(); } public void test(String str) { threadLocal_str = str; ThreadLocalTest.sleep(1000); System.out.println("ThreadLocal-Normal Test : " + threadLocal_str); } public static void main(String[] args) { // normalTest(); threadLocalTest(); } private static void threadLocalTest() { ThreadLocalTest localTest = new ThreadLocalTest(); Runnable one = () -> localTest.test_thread_local("test1"); Runnable two = () -> localTest.test_thread_local("test2"); Thread thread1 = new Thread(one); thread1.setName("thread1"); Thread thread2 = new Thread(two); thread2.setName("thread2"); thread1.start(); ThreadLocalTest.sleep(100); thread2.start(); ThreadLocalTest.sleep(3000); } private static void normalTest() { ThreadLocalTest localTest = new ThreadLocalTest(); Runnable one = () -> localTest.test("test1"); Runnable two = () -> localTest.test("test2"); Thread thread1 = new Thread(one); thread1.setName("thread1"); Thread thread2 = new Thread(two); thread2.setName("thread2"); thread1.start(); ThreadLocalTest.sleep(100); thread2.start(); ThreadLocalTest.sleep(3000); } private static void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
반응형

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.