이 글은 원 저자 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 |