자바 & 스프링

ThreadLocal의 정의와 사용법

p829911 2021. 12. 20. 19:05

Synchronized 키워드와 더불어 자바에서 제공하는 멀티 쓰레드를 위한 도구로 ThreadLocal이 있다.
ThreadLocal은 각 쓰레드가 자신만의 전역변수를 만들어 사용할 수 있는 기능을 제공해준다. 오직 한 쓰레드에 의해서 읽고 쓰여질 수 있는 변수라고 생각하면 된다. ThreadLocal 변수를 선언하면 멀티쓰레드 환경에서 각 쓰레드마다 독립적인 변수를 가지고 접근할 수 있다.


코드

public class ThreadLocalTest {
    public static class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("thread name = " + Thread.currentThread().getName() + ", index = " + index.get());
            index.set("name" + index.get());
            System.out.println("thread name = " + Thread.currentThread().getName() + ", index = " + index.get());
        }
    }

    private static final ThreadLocal<String> index = ThreadLocal.withInitial(() -> Thread.currentThread().getName());


    public static void main(String[] args) {
        Runnable runnable = new MyThread();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(runnable, Integer.toString(i));
            t.start();
        }
    }
}

결과

더보기

thread name = 5, index = 5
thread name = 0, index = 0
thread name = 4, index = 4
thread name = 3, index = 3
thread name = 1, index = 1
thread name = 2, index = 2
thread name = 6, index = 6
thread name = 9, index = 9
thread name = 7, index = 7
thread name = 8, index = 8
thread name = 7, index = name7
thread name = 8, index = name8
thread name = 4, index = name4
thread name = 3, index = name3
thread name = 0, index = name0
thread name = 2, index = name2
thread name = 5, index = name5
thread name = 9, index = name9
thread name = 1, index = name1
thread name = 6, index = name6


실행결과를 보면 서로 다른 쓰레드의 index에 간섭을 일으키지 않았다. 각 쓰레드는 공통적으로 index 변수에 접근하여 get(), set() 메소드를 사용한다. 이 경우 각 쓰레드들은 자신에게 할당된 index에 접근하게 되므로 다른 쓰레드의 index에 접근할 수 없다.

Thread 객체는 ThreadLocal.ThreadLocalMap threadLocals = null; 이라는 변수를 가지고 있는데 배열로 관리되고 있다. (Entry[], 초기 크기 16) ThreadLocal 변수는 Thread 객체에 정보를 달아놔서 쓰레드 동기화를 필요없게 만들어 놓은 방법이다.


주의점

ThreadLocal은 메모리 누수의 주범이 됨으로 주의해서 사용해야 한다.

Thread Pool 환경에서 ThreadLocal을 사용하는 경우 변수에 보관된 데이터 사용이 끝나면 반드시 해당 데이터를 삭제해 주어야 한다.(remove()) 그렇지 않을 경우 재사용되는 쓰레드가 올바르지 않은 데이터를 참조할 수 있다.