Java ThreadLocal 예제

Java ThreadLocal은 스레드 로컬 변수를 생성하는 데 사용됩니다. 객체의 모든 스레드가 변수를 공유하므로 변수는 스레드 안전하지 않습니다. 우리는 스레드 안전성을 위해 동기화를 사용할 수 있지만 동기화를 피하려면 ThreadLocal 변수를 사용할 수 있습니다.

Java ThreadLocal

각 스레드는 자체적인 ThreadLocal 변수를 가지며, get() 및 set() 메서드를 사용하여 기본값을 가져오거나 해당 값을 스레드에 대해 지역적으로 변경할 수 있습니다. ThreadLocal 인스턴스는 일반적으로 스레드와 상태를 연결하려는 클래스의 private static 필드입니다.

Java ThreadLocal 예제

다음은 자바 프로그램에서 ThreadLocal 사용을 보여주고 각 스레드가 자체적인 ThreadLocal 변수의 사본을 가지고 있음을 증명하는 작은 예제입니다. ThreadLocalExample.java

package com.journaldev.threads;

import java.text.SimpleDateFormat;
import java.util.Random;

public class ThreadLocalExample implements Runnable{

    // SimpleDateFormat은 스레드 안전하지 않으므로 각 스레드에 하나씩 제공합니다
    private static final ThreadLocal formatter = new ThreadLocal(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };
    
    public static void main(String[] args) throws InterruptedException {
        ThreadLocalExample obj = new ThreadLocalExample();
        for(int i=0 ; i<10; i++){
            Thread t = new Thread(obj, ""+i);
            Thread.sleep(new Random().nextInt(1000));
            t.start();
        }
    }

    @Override
    public void run() {
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
        try {
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //스레드에서 포맷터 패턴이 변경되었지만 다른 스레드에는 반영되지 않습니다
        formatter.set(new SimpleDateFormat());
        
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
    }

}

위의 자바 ThreadLocal 예제 프로그램의 출력은 다음과 같습니다:

Thread Name= 0 default Formatter = yyyyMMdd HHmm
Thread Name= 1 default Formatter = yyyyMMdd HHmm
Thread Name= 0 formatter = M/d/yy h:mm a
Thread Name= 2 default Formatter = yyyyMMdd HHmm
Thread Name= 1 formatter = M/d/yy h:mm a
Thread Name= 3 default Formatter = yyyyMMdd HHmm
Thread Name= 4 default Formatter = yyyyMMdd HHmm
Thread Name= 4 formatter = M/d/yy h:mm a
Thread Name= 5 default Formatter = yyyyMMdd HHmm
Thread Name= 2 formatter = M/d/yy h:mm a
Thread Name= 3 formatter = M/d/yy h:mm a
Thread Name= 6 default Formatter = yyyyMMdd HHmm
Thread Name= 5 formatter = M/d/yy h:mm a
Thread Name= 6 formatter = M/d/yy h:mm a
Thread Name= 7 default Formatter = yyyyMMdd HHmm
Thread Name= 8 default Formatter = yyyyMMdd HHmm
Thread Name= 8 formatter = M/d/yy h:mm a
Thread Name= 7 formatter = M/d/yy h:mm a
Thread Name= 9 default Formatter = yyyyMMdd HHmm
Thread Name= 9 formatter = M/d/yy h:mm a

보시다시피 Thread-0은 formatter의 값을 변경했지만 thread-2의 기본 formatter는 초기화된 값과 동일합니다. 다른 스레드에 대해서도 동일한 패턴을 볼 수 있습니다. 업데이트: ThreadLocal 클래스는 Java 8에서 Supplier 함수 인터페이스를 인수로 취하는 새로운 메서드 withInitial()으로 확장되었습니다. 따라서 우리는 람다 표현식을 사용하여 ThreadLocal 인스턴스를 쉽게 생성할 수 있습니다. 예를 들어, 위의 formatter ThreadLocal 변수는 다음과 같이 한 줄로 정의될 수 있습니다:

private static final ThreadLocal<SimpleDateFormat> formatter = 
	ThreadLocal.<SimpleDateFormat>withInitial
	(() -> {return new SimpleDateFormat("yyyyMMdd HHmm");});

Java 8 기능이 처음이라면 Java 8 기능Java 8 함수형 인터페이스를 확인해보세요. 이것이 자바 프로그래밍에서의 ThreadLocal에 관한 모든 것입니다. 참고: API 문서

Source:
https://www.digitalocean.com/community/tutorials/java-threadlocal-example