자바 병렬 프로 그래 밍 의 ThreadLocal 상세 설명 및 인 스 턴 스
11462 단어 Java병발 하 다ThreadLocal
요약:
ThreadLocal 은 스 레 드 부분 변수 라 고도 부 르 는데 자바 에서 비교적 특수 한 스 레 드 바 인 딩 체제 로 변수 가 서로 다른 스 레 드 간 의 격 리 성 을 확보 하여 모든 스 레 드 가 자신의 상 태 를 처리 하 는 데 편리 하도록 합 니 다.더 나 아가 본 고 는 ThreadLocal 류 의 소스 코드 를 착안점 으로 삼 아 ThreadLocal 류 의 역할 원 리 를 깊이 분석 하고 응용 장면 과 일반 사용 절 차 를 제시 했다.
ThreadLocal 에 대한 이해
1).ThreadLocal 개요
ThreadLocal 은 스 레 드 부분 변수 라 고도 부 르 는데 자바 에서 비교적 특수 한 스 레 드 바 인 딩 체제 로 이 변 수 를 사용 하 는 스 레 드 에 변수 값 의 사본 을 제공 할 수 있 으 며 모든 스 레 드 는 자신의 사본 을 독립 적 으로 바 꿀 수 있 으 며 다른 라인 의 사본 과 충돌 하지 않 습 니 다.ThreadLocal 을 통 해 액세스 하 는 데 이 터 는 항상 현재 스 레 드 와 관련 이 있 습 니 다.즉,JVM 은 모든 실행 스 레 드 에 개인 적 인 로 컬 인 스 턴 스 액세스 공간 을 연결 하여 다 중 스 레 드 환경 에서 자주 발생 하 는 동시 방문 문제 에 격 리 체 제 를 제공 합 니 다.
2).ThreadLocal 의 JDK 정의
ThreadLocal
이 클래스 는 스 레 드-로 컬 변 수 를 제공 합 니 다.이 변 수 는(get 또는 set 메 서 드 를 통 해)하나 에 액세스 하 는 각 스 레 드 에 자체 적 으로 액세스 하 는 일반 대응(사본)과 다 릅 니 다. independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
각 스 레 드 는 스 레 드 가 살아 있 고 ThreadLocal 인 스 턴 스 가 액세스 할 수 있 는 한 스 레 드-로 컬 변수의 복사 본 에 대한 암시 적 참 조 를 보유 합 니 다.after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
우 리 는 그 중에서 세 가지 요점 을 뽑 을 수 있다.
모든 스 레 드 에는 이 ThreadLocal 변수 에 대한 개인 값 이 있 습 니 다.
모든 스 레 드 는 다른 스 레 드 에 독립 된 컨 텍스트 로 이 변수의 값 을 저장 하고 다른 스 레 드 는 보이 지 않 습 니 다.
변수의 초기 값 에 독립
ThreadLocal 은 초기 값 을 지정 할 수 있 습 니 다.그러면 모든 스 레 드 는 이 초기 화 값 의 복사 본 을 얻 을 수 있 고 모든 스 레 드 가 이 값 에 대한 수정 은 다른 스 레 드 에 보이 지 않 습 니 다.
상태 가 어떤 스 레 드 와 연결 되 어 있 습 니 다.
ThreadLocal 은 공유 변수의 문 제 를 해결 하 는 데 사용 되 는 것 이 아니 라 스 레 드 동기 화 를 조율 하기 위해 존재 하 는 것 이 아니 라 모든 스 레 드 가 자신의 상 태 를 처리 하 는 데 편리 하도록 도 입 된 메커니즘 입 니 다.이 점 을 이해 하 는 것 이 ThreadLocal 을 정확하게 사용 하 는 데 중요 합 니 다.
3).응용 장면
클래스 ThreadLocal 은 모든 스 레 드 에 자신의 값 을 연결 하여 자신의 상 태 를 처리 하 는 데 편리 하도록 하 는 것 을 해결 합 니 다.구체 적 으로 말 하면 ThreadLocal 변 수 를 전역 적 으로 데 이 터 를 저장 하 는 상자 에 비유 할 수 있 고 상자 에 모든 스 레 드 의 개인 데 이 터 를 저장 할 수 있 습 니 다.예 를 들 어 다음 종 류 는 모든 스 레 드 에 대한 유일한 부분 식별 자 를 만 드 는 데 사용 된다.스 레 드 ID 는 유 니 크 Num.get()을 처음 호출 할 때 분 배 됩 니 다.후속 호출 에 서 는 변경 되 지 않 습 니 다.
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueThreadIdGenerator {
private static final AtomicInteger uniqueId = new AtomicInteger(0);
private static final ThreadLocal<Integer> uniqueNum = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return uniqueId.getAndIncrement();
}
};
public static void main(String[] args) {
Thread[] threads = new Thread[5];
for (int i = 0; i < 5; i++) {
String name = "Thread-" + i;
threads[i] = new Thread(name){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": "
+ uniqueNum.get());
}
};
threads[i].start();
}
System.out.println(Thread.currentThread().getName() + ": "
+ uniqueNum.get());
}
}/* Output( ):
Thread-1: 2
Thread-0: 0
Thread-2: 3
main: 1
Thread-3: 4
Thread-4: 5
*///:~
2.ThreadLocal 류 깊이 분석다음은 ThreadLocal 의 구체 적 인 실현 을 살 펴 보 겠 습 니 다.이 유형 은 모두 네 가지 방법 을 제공 합 니 다.
public T get() { }
public void set(T value) { }
public void remove() { }
protected T initialValue() { }
그 중에서 get()방법 은 ThreadLocal 변수 가 현재 스 레 드 에 저 장 된 값 을 가 져 오 는 것 입 니 다.set()는 ThreadLocal 변수 가 현재 스 레 드 에 있 는 값 을 설정 하 는 데 사 용 됩 니 다.reove()는 현재 스 레 드 와 관련 된 ThreadLocal 변 수 를 제거 하 는 데 사 용 됩 니 다.initialValue()는 proctected 방법 으로 재 작성 이 필요 합 니 다.1.원리 탐구
1).착안점:get()
우선,우 리 는 먼저 그 소스 코드 를 본다.
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread(); //
ThreadLocalMap map = getMap(t); // threadLocals
if (map != null) {
// ThreadLocalMap thread-local variable entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value; //
}
return setInitialValue();
}
2).관건:setInitialValue()
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue(); // null
Thread t = Thread.currentThread(); //
ThreadLocalMap map = getMap(t); // ThreadLocalMap threadLocals
if (map != null)
map.set(this, value); // map ThreadLocal
else
createMap(t, value);
return value;
}
우 리 는 이 어 상기 방법 과 관련 된 세 가지 방법 을 살 펴 보 았 다.initial Value(),set(this,value)와 createMap(t,value)이다.(1) initialValue()
/**
* Returns the current thread's "initial value" for this
* thread-local variable. This method will be invoked the first
* time a thread accesses the variable with the {@link #get}
* method, unless the thread previously invoked the {@link #set}
* method, in which case the <tt>initialValue</tt> method will not
* be invoked for the thread. Normally, this method is invoked at
* most once per thread, but it may be invoked again in case of
* subsequent invocations of {@link #remove} followed by {@link #get}.
*
* <p>This implementation simply returns <tt>null</tt>; if the
* programmer desires thread-local variables to have an initial
* value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
* subclassed, and this method overridden. Typically, an
* anonymous inner class will be used.
*
* @return the initial value for this thread-local
*/
protected T initialValue() {
return null; // null
}
(2) createMap()
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); // this ThreadLocal , map
}
이로써 대부분의 친구 들 은 ThreadLocal 클래스 가 각 라인 에 변 수 를 만 드 는 복사 본 을 어떻게 만 드 는 지 알 게 되 었 을 것 입 니 다.① 모든 스 레 드 Thread 내부 에 ThreadLocal.ThreadLocalMap 형식의 구성원 변수 threadLocals 가 있 습 니 다.이 threadLocals 는 실제 ThreadLocal 변수 사본 을 저장 하 는 데 사 용 됩 니 다.키 값 은 현재 ThreadLocal 변수 이 고 value 는 변수의 사본(값)입 니 다.
② 처음에 Thread 에 서 는 threadLocals 가 비어 있 습 니 다.ThreadLocal 변 수 를 통 해 get()방법 이나 set()방법 을 호출 하면 Thread 클래스 의 threadLocals 를 초기 화하 고 현재 ThreadLocal 변 수 를 키 로 하여 ThreadLocal 에 저장 할 값 을 value 로 하여 threadLocals 에 저장 합 니 다.
③ 그리고 현재 스 레 드 에서 던 전 변 수 를 사용 하려 면 get 방법 으로 해당 스 레 드 의 thread Locals 에서 찾 을 수 있 습 니 다.
2.사례 검증
다음은 하나의 예 를 통 해 ThreadLocal 을 통 해 모든 스 레 드 에서 변수 던 전 을 만 드 는 효 과 를 증명 합 니 다.
public class Test {
ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
ThreadLocal<String> stringLocal = new ThreadLocal<String>();
public void set() {
longLocal.set(Thread.currentThread().getId());
stringLocal.set(Thread.currentThread().getName());
}
public long getLong() {
return longLocal.get();
}
public String getString() {
return stringLocal.get();
}
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
test.set();
System.out.println(" main :");
System.out.println(test.getLong());
System.out.println(test.getString());
Thread thread1 = new Thread() {
public void run() {
test.set();
System.out.println("
Thread-0 :");
System.out.println(test.getLong());
System.out.println(test.getString());
};
};
thread1.start();
}
}/* Output:
main :
1
main
Thread-0 :
12
Thread-0
*///:~
이 코드 의 출력 결 과 를 통 해 알 수 있 듯 이 main 스 레 드 와 thread 1 스 레 드 에서 longLocal 에 저 장 된 던 전 값 과 stringLocal 에 저 장 된 던 전 값 이 다 르 고 더 나 아가 알 수 있 습 니 다.자바 에서 클래스 ThreadLocal 은 변수 가 서로 다른 스 레 드 간 의 격 리 성 을 해결 합 니 다.가장 흔히 볼 수 있 는 ThreadLocal 사용 장면 은 데이터베이스 연결 문제,Session 관리 등 이 있다.
(1)데이터베이스 연결 문제
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
(2)세 션 관리
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
4.ThreadLocal 일반 사용 절차ThreadLocal 사용 절 차 는 일반적으로 세 단계 로 나 뉜 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.