이 글은 원 저자 Jakob Jenkov의 허가로 포스팅된 번역물이다.

원문 URL : http://tutorials.jenkov.com/java-concurrency/threadlocal.html



자바 ThreadLocal 클래스는 오직 한 쓰레드에 의해 읽고 쓰여질 수 있는 변수를 생성할 수 있도록 한다. 때문에 만일 두 쓰레드가 같은 코드를 실행하고 이 코드가 하나의 ThreadLocal 변수를 참조하더라도, 이 두 쓰레드는 서로의 ThreadLocal 변수를 볼 수 없다. 글자 그대로 쓰레드의 지역변수이다.



쓰레드로컬 생성


다음은 ThreadLocal 을 생성하는 간단한 예제이다:


private ThreadLocal myThreadLocal = new ThreadLocal();


보다시피, 새로운 ThreadLocal 객체를 생성했다. 이 코드는 오직 한 쓰레드 당 한 번의 실행을 허용하여, 다수의 쓰레드에 의한 실행에도 각 쓰레드는 자신들 각자의 ThreadLocal 인스턴스를 가지게 된다. 두 쓰레드가 각자의 변수를 ThreadLocal 객체에 세팅했다면, 쓰레드들은 서로 다른 ThreadLocal 변수값을 가지게 되며, 오직 자신의 변수만 볼 수 있게 된다.



쓰레드로컬 다루기


쓰레드로컬을 생성하면 다음과 같은 방법으로 쓰레드로컬에 값을 저장할 수 있다:


myThreadLocal.set("A thread local value");


다음으로 쓰레드로컬의 값을 읽는 방법은 다음과 같다:


String threadLocalValue = (String) myThreadLocal.get();


get() 메소드는 Object 타입 객체를 반환하고, set() 메소드 역시 Object 타입을 파라미터로 받는다.



쓰레드로컬 제너릭


쓰레드로컬은 변수 타입을 다루기 쉽도록, 제너릭으로 생성 가능하다:


private ThreadLocal myThreadLocal = new ThreadLocal<String>();
myThreadLocal.set("Hello ThreadLocal");

String threadLocalValue = myThreadLocal.get();



쓰레드로컬 변수 초기화


쓰레드로컬 객체에 세팅한 값은 오직 값을 세팅한 쓰레드만 접근할 수 있기 때문에, 모든 쓰레드가 사용할 수 있는 쓰레드로컬 초기값(디폴트)은 없다. 대신, 쓰레드로컬을 서브클래싱하고 initialValue() 메소드를 오버라이딩하는 방법으로 쓰레드로컬의 초기값을 설정할 수 있다:


private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
    @Override protected String initialValue() {
        return "This is the initial value";
    }
};  


이제 이 코드를 이용하는 모든 쓰레드들은 set() 메소드로 값을 세팅하지 않아도 get() 메소드를 호출하면 이 초기값을 볼 수 있을 것이다.



쓰레드로컬 예제


다음은 쓰레드로컬 예제이다:


public class ThreadLocalExample {


    public static class MyRunnable implements Runnable {

        private ThreadLocal<Integer> threadLocal =
               new ThreadLocal<Integer>();

        @Override
        public void run() {
            threadLocal.set( (int) (Math.random() * 100D) );
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
    
            System.out.println(threadLocal.get());
        }
    }


    public static void main(String[] args) {
        MyRunnable sharedRunnableInstance = new MyRunnable();

        Thread thread1 = new Thread(sharedRunnableInstance);
        Thread thread2 = new Thread(sharedRunnableInstance);

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

        thread1.join(); //wait for thread 1 to terminate
        thread2.join(); //wait for thread 2 to terminate
    }

}


이 예제는 Runnable 인스턴스인 MyRunnable 클래스의 인스턴스를 1개 생성하여 두 개의 다른 쓰레드에게 전달한다. 각 쓰레드는 run() 메소드를 호출하고, ThreadLocal 인스턴스에 각자 다른 값을 세팅한다. 만약 여기서 ThreadLocal 객체가 없고 set() 메소드 호출부가 동기화(synchronized)되어 있다면, 두 번째 쓰레드의 값이 첫 번째 쓰레드가 세팅한 값을 덮어쓸 것이다.


하지만 여기선 ThreadLocal 객체가 있고, 두 쓰레드는 서로의 값에 접근하지 않은 채로 각자의 값을 가진다.



InheritableThreadLocal


InheritableThreadLocal 클래스는 ThreadLocal 클래스의 서브클래스이다. ThreadLocal 은 모든 쓰레드가 각자의 값을 가지게 하지만, InheritableThreadLocal 은 자신에게 세팅된 값을, 값을 세팅한 쓰레드는 물론이고 이 쓰레드에 의해 생성된 자식 쓰레드들도 볼 수 있도록 한다.



'Java > Concurrency' 카테고리의 다른 글

데드락(Deadlock)  (0) 2017.04.09
쓰레드 시그널링  (0) 2017.04.09
자바 volatile 키워드  (2) 2017.04.09
자바 동기화 블록(Java Synchronized Blocks)  (0) 2017.04.09
자바 메모리 모델  (2) 2017.04.09

+ Recent posts