수색…


비고

호출을 호출 할 때 내부 객체에 의존하지만 SimpleDateFormat , Marshaller 와 같이 그렇지 않으면 stateless 인 객체에 가장 많이 사용됩니다.

들어 Random 의 ThreadLocal 사용, 사용을 고려 ThreadLocalRandom

ThreadLocal Java 8 기능 초기화

public static class ThreadLocalExample
{
    private static final ThreadLocal<SimpleDateFormat> format = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd_HHmm"));

    public String formatDate(Date date)
    {
        return format.get().format(date);
    }
}

기본 ThreadLocal 사용법

Java ThreadLocal 은 스레드 로컬 변수를 만드는 데 사용됩니다. Object의 스레드는 변수를 공유하므로 변수가 스레드로부터 안전하지 않은 것으로 알려져 있습니다. 스레드 안전성을 위해 동기화를 사용할 수 있지만 동기화를 피하려면 ThreadLocal을 사용하여 스레드에 로컬 인 변수를 만들 수 있습니다. 즉, 해당 스레드 만 해당 변수를 읽거나 쓸 수 있으므로 다른 스레드가 동일한 코드를 실행합니다 서로 다른 ThreadLocal 변수에 액세스 할 수 없습니다.

ThreadLocal 변수를 사용할 수 있습니다. 예를 들어 웹 서비스와 같은 스레드 풀이있는 상황에서. 예를 들어 매 요청마다 매번 SimpleDateFormat 객체를 만드는 작업은 시간이 많이 걸리고 SimpleDateFormat 은 스레드로부터 안전하지 않으므로 Static SimpleDateFormat 를 만들 수 없기 때문에 모든 SimpleDateFormat 을 만드는 오버 헤드없이 스레드 안전 작업을 수행 할 수 있도록 ThreadLocal을 만들 수 있습니다 시각.

아래 코드는이 코드를 사용하는 방법을 보여줍니다.

모든 스레드는 자신의 ThreadLocal 변수를 가지고 있으며 get()set() 메서드를 사용하여 기본값을 얻거나 Thread에 대한 로컬 값을 변경할 수 있습니다.

ThreadLocal 인스턴스는 일반적으로 상태를 스레드와 연결하려는 클래스의 개인 정적 필드입니다.

다음은 Java 프로그램에서 ThreadLocal을 사용하고 모든 스레드에 ThreadLocal 변수의 자체 복사본이 있음을 보여주는 작은 예제입니다.

package com.examples.threads;

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

public class ThreadLocalExample implements Runnable{

    // SimpleDateFormat is not thread-safe, so give one to each thread
 // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @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());
    }

}

산출:

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은 포맷터의 값을 변경했지만 여전히 thread-2 기본 포맷터는 초기화 된 값과 같습니다.

공유 객체가 하나 인 다중 스레드

이 예제에서는 하나의 객체 만 있지만 다른 스레드간에 공유 / 실행됩니다. 상태를 저장하기위한 필드의 일반적인 사용은 불가능합니다. 왜냐하면 다른 스레드도이 스레드를 볼 수 있기 때문입니다 (또는 아마도 보이지 않을 수도 있기 때문입니다).

public class Test {
    public static void main(String[] args) {
        Foo foo = new Foo();
        new Thread(foo, "Thread 1").start();
        new Thread(foo, "Thread 2").start();
    }
}

Foo에서는 0부터 시작합니다. 상태를 필드에 저장하는 대신 정적으로 액세스 할 수있는 ThreadLocal 객체에 현재 숫자를 저장합니다. 이 예제의 동기화는 ThreadLocal의 사용과 관련이 없으며 더 나은 콘솔 출력을 보장합니다.

public class Foo implements Runnable {
    private static final int ITERATIONS = 10;
    private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    @Override
    public void run() {
        for (int i = 0; i < ITERATIONS; i++) {
            synchronized (threadLocal) {
                //Although accessing a static field, we get our own (previously saved) value.
                int value = threadLocal.get();
                System.out.println(Thread.currentThread().getName() + ": " + value);
                
                //Update our own variable
                threadLocal.set(value + 1);

                try {
                    threadLocal.notifyAll();
                    if (i < ITERATIONS - 1) {
                        threadLocal.wait();
                    }
                } catch (InterruptedException ex) {
                }
            }
        }
    }
}

출력에서 우리는 각각의 쓰레드가 스스로 카운트하고 다른 쓰레드의 값을 사용하지 않는다는 것을 알 수 있습니다 :

Thread 1: 0
Thread 2: 0
Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
Thread 1: 3
Thread 2: 3
Thread 1: 4
Thread 2: 4
Thread 1: 5
Thread 2: 5
Thread 1: 6
Thread 2: 6
Thread 1: 7
Thread 2: 7
Thread 1: 8
Thread 2: 8
Thread 1: 9
Thread 2: 9


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow