Java Language
ThreadLocal
수색…
비고
호출을 호출 할 때 내부 객체에 의존하지만 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