Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

Note

쓰레드 로컬 (Thread Local) 본문

Dev/Web

쓰레드 로컬 (Thread Local)

__Cindy__ 2023. 3. 3. 21:53

쓰레드 로컬(Thread Local)은 멀티쓰레드 환경에서 쓰레드 간 공유되는 전역 변수의 문제를 해결하기 위해 사용되는 기술이다

 

쓰레드 로컬을 사용하면 전역 변수를 각 쓰레드 별로 개별적으로 유지할 수 있다. 이렇게 하면 각 쓰레드가 전역 변수를 독립적으로 사용할 수 있으므로, 다른 쓰레드에서의 작업에 영향을 받지 않고 안전하게 사용할 수 있다.

쓰레드 로컬 변수는 일반적으로 ThreadLocal 클래스를 사용하여 생성한다. 이 클래스는 각 쓰레드가 자신만의 값을 저장하고 사용할 수 있는 변수를 생성하는데 사용된다. 각 쓰레드는 ThreadLocal 변수를 생성할 때 해당 변수에 대한 고유한 인스턴스를 생성한다. 이렇게 함으로써 각 쓰레드는 서로 독립적인 값이 저장된 고유한 변수 인스턴스를 사용할 수 있게 된다.

 

Java 에서는  java.lang.ThreadLocal  클래스를 제공한다.

https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html

 

사용법

- 조회 : ThreadLocal.get()

- 저장 : ThreadLocal.set(data)

- 제거 : ThreadLocal.remove()

 

예제)

public class ThreadLocalExample {

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int value = threadLocal.get();
                System.out.println(Thread.currentThread().getName() + " : initial value - " + value);
                threadLocal.set(10);
                value = threadLocal.get();
                System.out.println(Thread.currentThread().getName() + " : updated value - " + value);
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                int value = threadLocal.get();
                System.out.println(Thread.currentThread().getName() + " : initial value - " + value);
                threadLocal.set(20);
                value = threadLocal.get();
                System.out.println(Thread.currentThread().getName() + " : updated value - " + value);
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
    }
}

실행결과

Thread-0 : initial value - 0
Thread-0 : updated value - 10
Thread-1 : initial value - 0
Thread-1 : updated value - 20

-> 동일한 변수를 단순히 수정한 후 조회하는 예제. 동시성 문제가 발생하지 않고 각 쓰레드별로 독립적으로 동작한다.

 

쓰레드 로컬 변수를 사용하면 쓰레드 간 동기화 문제를 해결할 수 있으며, 쓰레드 간 데이터 공유에 따른 오류를 방지할 수 있다. 그러나 쓰레드 로컬 변수는 메모리 사용량이 높아질 수 있고, 잘못 사용하면 오류가 발생할 수 있으므로 주의해서 사용해야 한다.

 

특히 쓰레드 풀(Thread Pool)과 함께 사용할 때 주의해야한다.

쓰레드 풀은 미리 생성된 스레드를 사용하여 작업을 처리하므로 (쓰레드 생성비용 때문에), 같은 쓰레드가 다음 작업을 처리할 수 있도록 재사용된다. 이러한 경우에는 쓰레드 로컬이 이전 작업에서 설정된 값을 계속 유지하게 된다. 따라서 이전 작업에서 설정된 값이 다음 작업에서도 계속 유지되어 의도하지 않은 결과를 가져올 수 있다.

예를 들어, 쓰레드 풀에서 실행되는 쓰레드에서 로깅 작업을 수행하는 경우, 로깅 작업에서 사용하는 로그 레벨이 쓰레드 로컬에 저장되어 있다면 이전 작업에서 설정된 로그 레벨이 다음 작업에서 계속 사용되므로, 다음 작업에서 의도하지 않은 로그가 출력될 수 있다.

이런 문제를 방지하려면, 쓰레드 풀에서 작업을 처리할 때마다 쓰레드 로컬을 초기화하거나, 쓰레드 풀에서 각 쓰레드에 대해 새로운 쓰레드 로컬 객체를 생성하는 방법을 사용할 수 있다. 또는 쓰레드 로컬 대신 다른 Thread-Safe 한 방법을 사용하여 작업을 처리해야 한다.

 

 

'Dev > Web' 카테고리의 다른 글

JPA Programming  (0) 2021.06.16
REST API  (0) 2021.06.11