ThreadLocal의 디자인 및 사용(원리편)
스레드 국부 변수(ThreadLocal)의 기능은 매우 간단하다. 이 변수를 사용하는 모든 스레드에 변수 값의 복사본을 제공하는 것이다. 모든 스레드는 독립적으로 자신의 복사본을 바꿀 수 있고 다른 스레드의 복사본과 충돌하지 않는다.라인의 각도에서 보면 모든 라인이 이 변수를 완전히 가지고 있는 것 같다.
먼저 ThreadLocal 클래스의 인터페이스와 디자인 방향을 살펴보겠습니다.J2SE5.0에서 이 클래스는 기본 구조 함수 1개와 일반 함수 4개가 있습니다: 보호된 ThreadLocal initial Value () 는 하위 클래스를 다시 쓰기 위해 일부러 이루어진 것입니다.이 방법은 현재 스레드가 이 스레드 국부 변수의 초기 값을 되돌려줍니다. 이 방법은 한 스레드가 get () 또는 set (Object) 을 처음 호출할 때 실행되고, 1회만 실행됩니다.public ThreadLocal get (), 현재 스레드의 로컬 변수 복사본을 되돌려줍니다.public void set(ThreadLocal value), 현재 스레드의 스레드 부분 변수 복사본의 값을 설정합니다.public void remove (), 현재 스레드의 스레드 국부 변수 복사본의 값을 제거하여 저장 공간을 방출합니다.
다음 참조를 통해 ThreadLocal의 작동 방식을 확인할 수 있습니다.
public class ThreadLocal {
private Map values = Collections.synchronizedMap(new HashMap());
public Object get() {
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread)) {
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue) {
values.put(Thread.currentThread(), newValue);
}
public Object initialValue() {
return null;
}
}
JDK에서 ThreadLocal의 실현은 전체적인 사고방식도 이와 유사하지만 이것은 공업 강도의 실현이 아니다.우선 get () 과 set () 작업은values 맵의 동기화가 필요하며, 여러 라인이 같은 ThreadLocal에 동시에 접근하면 충돌이 발생합니다.그 밖에 이 실현도 실제와 부합되지 않는다. Thread 대상으로values 맵의 키를 만들면 라인이 종료된 후에Thread에 대해 쓰레기 회수를 할 수 없을 뿐만 아니라 죽은 라인의ThreadLocal의 특정한 라인의 값에 대해서도 쓰레기 회수를 할 수 없기 때문이다.j2sdk5.0의 src를 보면 ThreadLocal에 맵이 있는 것이 아니라 모든 Thread에 이런 맵이 존재한다. 구체적으로ThreadLocal이다.ThreadLocalMap.set을 사용할 때 현재 라인의 맵에 있는 put의 키는 현재 ThreadLocal 대상입니다.현재 Thread를 Key 값으로 Thread Local의 맵에 put하는 것이 아니라
ThreadLocal 사용스레드 부분 변수가 다른 값을 초기화하려면 ThreadLocal의 하위 클래스를 직접 실현하고 이 방법을 다시 써야 한다. 보통 inner anonymous class를 사용하여 ThreadLocal에 하위 클래스를 분류한다. 예를 들어 아래의 예에서 SerialNum 클래스는 모든 클래스에 하나의 순서 번호를 분배한다.
public class SerialNum {
// The next serial number to be assigned
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
}
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
}
스레드가 활성화되고 ThreadLocal 대상이 접근할 수 있을 때, 이 스레드는 이 스레드의 국부 변수 복사본에 대한 은밀한 인용을 가지고 있으며, 이 스레드의 운행이 끝난 후, 이 스레드가 가지고 있는 모든 스레드의 국부 변수 복사본은 효력을 상실하고 스팸 수집기가 수집하기를 기다릴 것이다.
ThreadLocal에서 어떤 종류의 대상을 보유할 수 있기 때문에 ThreadLocal을 사용하여 현재 스레드의 값을 가져오려면 강제 형식 변환이 필요합니다.하지만 J2SE5.0 모듈을 도입하면 새로운 모듈 파라미터를 지원하는 ThreadLocal
ThreadLocal은 다른 동기화 메커니즘에 비해 어떤 장점이 있습니까?ThreadLocal과 기타 모든 동기화 메커니즘은 다중 스레드에서 같은 변수에 대한 접근 충돌을 해결하기 위해 일반적인 동기화 메커니즘에서는 대상을 잠그고 여러 스레드가 같은 변수에 대한 안전한 접근을 실현한다.이때 이 변수는 여러 라인이 공유하는 것이다. 이런 동기화 메커니즘을 사용하면 언제 변수에 대해 읽기와 쓰기를 하는지, 언제 어떤 대상을 잠가야 하는지, 언제 이 대상의 자물쇠를 풀어야 하는지 세밀하게 분석해야 한다.이 모든 것은 여러 라인이 자원을 공유했기 때문이다.ThreadLocal은 다른 각도에서 다중 스레드의 병렬 접근을 해결한다. ThreadLocal은 모든 스레드에 이 스레드와 연결된 변수의 복사본을 유지하여 여러 스레드의 데이터를 격리하고 모든 스레드는 자신의 변수 복사본을 가지기 때문에 이 변수를 동기화할 필요가 없다.ThreadLocal은 다중 루틴 코드를 작성할 때 안전하지 않은 모든 변수를 ThreadLocal에 봉인하거나 그 대상의 특정한 루틴 상태를 ThreadLocal에 봉인할 수 있는 안전한 공유 대상을 제공합니다.
물론 ThreadLocal은 동기화 메커니즘을 대체할 수 없으며, 두 가지가 향하는 문제 영역은 다르다.동기화 메커니즘은 여러 개의 라인이 같은 자원에 대한 병렬 접근을 동기화하기 위한 것이고 여러 개의 라인 간에 통신을 하는 효과적인 방식이다.ThreadLocal은 여러 라인을 격리하는 데이터 공유로 근본적으로 여러 라인 사이에서 자원(변수)을 공유하지 않기 때문에 여러 라인을 동기화할 필요가 없다.따라서 여러 개의 라인 간의 통신이 필요하다면 동기화 메커니즘을 사용한다.만약 여러 개의 루트 간의 공유 충돌을 격리해야 한다면 ThreadLocal을 사용할 수 있습니다. 이것은 우리의 프로그램을 크게 간소화하고 프로그램을 더욱 읽기 쉽고 간결하게 할 것입니다.ThreadLocal 클래스는 각 스레드에 로컬 변수를 저장할 수 있는 장소를 제공합니다.
본질적으로 현재 실행 중인 Thread마다 맵이 있습니다. ThreadLocal 클래스는 이 맵에 대한 접근을 봉인합니다. 따라서 라인에서 새로 생성된 대상을 ThreadLocal을 통해 이 맵에 넣을 수 있습니다. 이로써 이 라인이 앞으로 ThreadLocal 대상 즉 이 맵에서 얻은 대상은 이 라인에서만 사용할 수 있고 다른 라인에 접근하지 않을 수 있습니다.
글에서 ThreadLocal의 디자인과 사용에 대해 언급한 바와 같이 다음과 같은 실현은 사실 옳지 않다.
public class ThreadLocal
{
private Map values = Collections.synchronizedMap(new HashMap());
public Object get()
{
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread))
{
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue)
{
values.put(Thread.currentThread(), newValue);
}
public Object initialValue()
{
return null;
}
}
실제로 ThreadLocal이 이 맵을 유지하는 것이 아니라 모든 Thread가 이 맵을 유지하는 것이다.이렇게 하면 매번 라인이 죽을 때마다 모든 맵에서 인용된 대상은 이 Thread의 죽음에 따라 쓰레기 수집기와 함께 수집된다. (물론 전제는 다른 곳에서 인용되지 않는다는 것이다)
이 맵의 키는 ThreadLocal 대상에 대한 약한 인용입니다. ThreadLocal 대상을 버릴 때 스팸 수집기는 이 키의 인용을 무시하고 ThreadLocal 대상을 삭제합니다.
Java Doc의 제안에 따라 ThreadLocal은 일반적으로 public static로 선언됩니다.
메소드 요약
T get()
이 스레드 국부 변수의 현재 스레드 복사본의 값을 되돌려줍니다.
protected T initialValue()
이 스레드의 국부 변수의 현재 스레드의 '초기값' 을 되돌려줍니다.
void remove()
이 스레드의 국부 변수 현재 스레드의 값을 제거합니다.
void set(T value)
이 스레드 국부 변수의 현재 스레드 복사본의 값을 지정한 값으로 설정합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
2022년 3월 21일 TIL1. JVM & JDK JVM JRE 자바 실행 환경의 약자로 자바 프로그램을 실행하기 위한 도구들이 들어있으며 JVM이 이 안에 포함된다 JDK JRE + 개발툴 javac는 컴파일 명령어 HelloWorld.cl...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.