ThreadLocal 이해
JDK 1.2 버 전에 서 자바. lang. ThreadLocal 을 제 공 했 고 ThreadLocal 은 다 중 스 레 드 프로그램의 병행 문 제 를 해결 하 는 데 새로운 방향 을 제공 했다.이 도구 류 를 사용 하면 아름 다운 다 중 스 레 드 프로그램 을 간결 하 게 작성 할 수 있다.
ThreadLocal 은 사람들 로 하여 금 글 을 읽 고 의 미 를 가지 게 하기 쉬 우 므 로 당연히 '로 컬 스 레 드' 라 고 생각 합 니 다.사실
ThreadLocal 은 Thread 가 아니 라 Thread 의 부분 변수 입 니 다. ThreadLocalVariable 이 라 고 부 르 는 것 이 더 이해 하기 쉬 울 수도 있 습 니 다.
ThreadLocal 유지보수 변 수 를 사용 할 때 ThreadLocal 은 이 변 수 를 사용 하 는 모든 스 레 드 에 독립 된 변수 사본 을 제공 하기 때문에 모든 스 레 드 는 자신의 사본 을 독립 적 으로 변경 할 수 있 으 며 다른 스 레 드 에 대응 하 는 사본 에 영향 을 주지 않 습 니 다.
스 레 드 의 측면 에서 볼 때 목표 변 수 는 스 레 드 의 로 컬 변수 와 같 습 니 다. 이것 도 유사 한 이름 에서 'Local' 이 표현 하고 자 하 는 뜻 입 니 다.
스 레 드 부분 변 수 는 자바 의 새로운 발명 이 아니 라 많은 언어 (예 를 들 어 IBM IBM XL FORTRAN) 가 문법 적 측면 에서 스 레 드 부분 변 수 를 제공 합 니 다.자바 에 서 는 언어 급 지원 이 아 닌 변형 적 으로 ThreadLocal 클래스 를 통 해 지원 합 니 다.
따라서 자바 에서 스 레 드 부분 변 수 를 만 드 는 코드 는 상대 적 으로 서 툴 기 때문에 스 레 드 부분 변 수 는 자바 개발 자 들 에 게 잘 보급 되 지 않 았 습 니 다.
ThreadLocal 인터페이스 방법
ThreadLocal 클래스 인 터 페 이 스 는 간단 합 니 다. 네 가지 방법 만 있 습 니 다. 먼저 알 아 보 겠 습 니 다.
void set(Object value)
현재 스 레 드 의 스 레 드 부분 변수의 값 을 설정 합 니 다.
public Object get () 이 방법 은 현재 스 레 드 에 대응 하 는 스 레 드 부분 변 수 를 되 돌려 줍 니 다.
public void remove () 는 현재 스 레 드 부분 변수의 값 을 삭제 합 니 다. 메모리 사용량 을 줄 이기 위해 서 입 니 다. 이 방법 은 JDK 5.0 에 추 가 된 방법 입 니 다.지적 해 야 할 것 은 스 레 드 가 끝 난 후에 해당 스 레 드 의 부분 변 수 는 자동 으로 쓰레기 로 회수 되 기 때문에 이 방법 으로 스 레 드 의 부분 변 수 를 제거 하 는 것 은 필수 적 인 작업 이 아니 지만 메모리 회수 속 도 를 가속 화 할 수 있다 는 것 이다.
proctected Object initialValue () 는 이 스 레 드 부분 변수의 초기 값 을 되 돌려 줍 니 다. 이 방법 은 proctected 방법 으로 하위 클래스 를 덮어 쓰기 위해 설계 되 었 습 니 다.이 방법 은 지연 호출 방법 으로 스 레 드 1 차 호출 get () 또는 set (Object) 시 에 만 실행 되 며 1 회 만 실 행 됩 니 다.ThreadLocal 의 부족 한 부분 은 null 로 직접 돌아 갑 니 다.
특히 JDK 5.0 에 서 는 ThreadLocal 이 범 형 을 지원 하고 있 으 며, 이러한 종류의 이름 은 ThreadLocal < T > 로 바 뀌 었 다.API 방법 도 상응 하 게 조정 되 었 다. 새로운 버 전의 API 방법 은 void set (T value), T get (), T initialValue () 이다.
ThreadLocal 은 어떻게 모든 스 레 드 유지 변 수 를 위 한 복사 본 을 만 듭 니까?사실 실현 하 는 사 고 는 매우 간단 하 다. ThreadLocal 류 에 하나의 Map 이 있 는데 모든 스 레 드 의 변수 사본 을 저장 하 는 데 사용 된다. Map 에서 요소 의 키 는 스 레 드 대상 이 고 값 은 스 레 드 에 대응 하 는 변수 사본 이다.우 리 는 스스로 간단 한 실현 버 전 을 제공 할 수 있다.
package test;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class SimpleThreadLocal {
private Map valueMap = Collections.synchronizedMap(new HashMap());
public void set(Object newValue) {
valueMap.put(Thread.currentThread(), newValue);// ① ,
}
public Object get() {
Thread currentThread = Thread.currentThread();
Object o = valueMap.get(currentThread);// ②
if (o == null && !valueMap.containsKey(currentThread)) {// ③ Map , Map 。
o = initialValue();
valueMap.put(currentThread, o);
}
return o;
}
public void remove() {
valueMap.remove(Thread.currentThread());
}
public Object initialValue() {
return null;
}
}
코드 목록 9 * 8209 ° 3 이 ThreadLocal 구현 버 전 은 유치 해 보이 지만 JDK 가 제공 하 는 ThreadLocal 류 와 실현 방향 은 비슷 하 다.
TheadLocal 인 스 턴 스
다음은 ThreadLocal 의 구체 적 인 사용 방법 을 구체 적 인 실례 를 통 해 알 아 보 겠 습 니 다.
코드 목록 2 SequenceNumber
package test;
public class SequenceNumber {
// ① ThreadLocal initialValue() ,
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
public Integer initialValue() {
return 0;
}
};
// ②
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
public static void main(String[] args){
SequenceNumber sn = new SequenceNumber();
// ③ 3 sn,
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
public void run(){
for (int i = 0; i < 3; i++) {// ④ 3
System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]");
}
}
}
}
일반적으로 저 희 는 익명 내부 클래스 를 통 해 ThreadLocal 의 하위 클래스 를 정의 하고 초기 변 수 를 제공 합 니 다. 예 를 들 어 ① 처 와 같 습 니 다.TestClient 스 레 드 는 ③ 곳 에서 3 개의 TestClient 를 만 들 고 같은 SequenceNumber 인 스 턴 스 를 공유 합 니 다.이상 코드 를 실행 하고 콘 솔 에서 다음 과 같은 결 과 를 출력 합 니 다.
thread[Thread-2] sn[1]
thread[Thread-0] sn[1]
thread[Thread-1] sn[1]
thread[Thread-2] sn[2]
thread[Thread-0] sn[2]
thread[Thread-1] sn[2]
thread[Thread-2] sn[3]
thread[Thread-0] sn[3]
thread[Thread-1] sn[3]
출력 결과 정 보 를 살 펴 보면 모든 스 레 드 에서 발생 하 는 번 호 는 같은 SequenceNumber 인 스 턴 스 를 공유 하지만 서로 간섭 하 는 상황 이 발생 하지 않 고 각자 독립 된 시리 얼 번 호 를 만 드 는 것 을 발견 했다. 이것 은 우리 가 ThreadLocal 을 통 해 모든 스 레 드 에 단독 복사 본 을 제공 하기 때문이다.
Thread 동기 화 메커니즘 비교
ThreadLocal 은 스 레 드 동기 화 체제 에 비해 어떤 장점 이 있 습 니까?ThreadLocal 과 스 레 드 동기 화 체 제 는 다 중 스 레 드 에서 같은 변수의 접근 충돌 문 제 를 해결 하기 위해 서 입 니 다.
동기 화 체제 에서 대상 의 잠 금 체 제 를 통 해 같은 시간 에 하나의 스 레 드 접근 변 수 를 확보 합 니 다.이때 이 변 수 는 여러 스 레 드 로 공 유 된 것 입 니 다. 동기 화 체 제 를 사용 하여 프로그램 이 언제 변 수 를 읽 고 쓰 는 지, 언제 대상 을 잠 그 고 언제 대상 자 물 쇠 를 풀 어야 하 는 지 등 복잡 한 문 제 를 신중하게 분석 해 야 합 니 다.
프로그램 설계 와 작성 이 상대 적 으로 어렵다.
그리고
ThreadLocal 은 다 중 스 레 드 의 동시 방문 을 다른 각도 에서 해결 합 니 다.ThreadLocal 은 모든 스 레 드 에 독립 된 변수 복사 본 을 제공 하여 여러 스 레 드 가 데이터 에 대한 접근 충돌 을 격 리 합 니 다.모든 스 레 드 는 자신의 변수 사본 을 가지 고 있 기 때문에 이 변 수 를 동기 화 할 필요 가 없습니다.ThreadLocal 은 스 레 드 안전 한 공유 대상 을 제공 합 니 다. 다 중 스 레 드 코드 를 작성 할 때 안전 하지 않 은 변 수 를 ThreadLocal 에 밀봉 할 수 있 습 니 다.
ThreadLocal 에 서 는 모든 종류의 대상 을 가 질 수 있 기 때문에 저 버 전 JDK 가 제공 하 는 get () 은 Object 대상 으로 되 돌아 가 며 강제 형식 변환 이 필요 합 니 다.그러나 JDK 5.0 은 범 형 을 통 해 이 문 제 를 잘 해 결 했 고 ThreadLocal 의 사용 을 어느 정도 간소화 했다. 코드 리스트 92 는 JDK 5.0 의 새로운 ThreadLocal < T > 버 전 을 사용 했다.
요약 하면 다 중 스 레 드 자원 공유 문제 에 대해
동기 화 메커니즘 은 '시간 으로 공간 을 바꾼다' 는 방식 을 채택 했다.
ThreadLocal 은 '공간 으로 시간 을 바꾼다' 는 방식 을 채택 했다.전 자 는 하나의 변 수 를 제공 하여 서로 다른 스 레 드 를 줄 지어 방문 하 게 하고 후 자 는 모든 스 레 드 에 변 수 를 제공 하기 때문에 서로 영향 을 주지 않 고 동시에 방문 할 수 있다.
Spring Thread Local 을 사용 하여 스 레 드 안전 문 제 를 해결 합 니 다.
우 리 는 일반적인 상황 에서 상태 가 없 는 Bean 만 이 다 중 스 레 드 환경 에서 공유 할 수 있다 는 것 을 알 고 있다. Spring 에서 대부분의 Bean 은 singleton 역할 영역 이 라 고 설명 할 수 있다.Spring 이 일부 Bean (예 를 들 어 Request ContextHolder, TransactionSynchronizationManager, Locale ContextHolder 등) 의 비 스 레 드 안전 상 태 를 ThreadLocal 로 처리 하여 스 레 드 안전 상태 로 만 들 었 기 때 문 입 니 다.
상태의 Bean (즉, 실행 후의 변수 값 이 다른 사람 에 의 해 수정 되 지 않 고 상태 불변성 을 유지 하 는 것) 은 다 중 스 레 드 에서 공유 할 수 있 습 니 다.
일반적인 웹 응용 은 표현 층, 서비스 층 과 지구 층 세 가지 차원 으로 나 뉘 는데 서로 다른 층 에서 대응 하 는 논 리 를 작성 하고 하층 은 인 터 페 이 스 를 통 해 상층 으로 기능 호출 을 개방 한다.일반적인 상황 에서 요청 을 받 고 응답 을 되 돌려 주 는 모든 프로그램 호출 은 하나의 스 레 드 에 속 합 니 다. 그림 9 * 8209 ° 2 참조:
그림 1 같은 스 레 드 가 3 층 을 관통 한다.
이렇게 하면 필요 에 따라 일부 비 스 레 드 안전 변 수 를 ThreadLocal 로 저장 할 수 있 습 니 다. 같은 요청 에 응 하 는 호출 스 레 드 에서 모든 관련 대상 이 같은 변 수 를 참조 할 수 있 습 니 다.
아래 의 실례 는 Spring 이 상태 가 있 는 Bean 에 대한 개조 사고방식 을 나 타 낼 수 있다.
코드 목록 3 TopicDao: 비 스 레 드 보안
public class TopicDao {
private Connection conn;①
public void addTopic(){
Statement stat = conn.createStatement();②
…
}
}
① 에 있 는 conn 은 구성원 변수 이기 때문에 addTopic () 방법 은 비 스 레 드 가 안전 하기 때문에 사용 할 때 새 TopicDao 인 스 턴 스 (비 singleton) 를 만들어 야 합 니 다.다음은 ThreadLocal 을 사용 하여 conn 이라는 비 스 레 드 안전 한 '상태' 를 개조 합 니 다.
코드 목록 4 TopicDao: 스 레 드 보안
package test;
import java.sql.Connection;
import java.sql.Statement;
public class TopicDao {
// ① ThreadLocal Connection
private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();
public static Connection getConnection() {
// ② connThreadLocal Connection Connection, 。
if (connThreadLocal.get() == null) {
Connection conn = ConnectionManager.getConnection();
connThreadLocal.set(conn);
return conn;
} else {
return connThreadLocal.get();// ③
}
}
public void addTopic() {
// ④ ThreadLocal Connection
Statement stat = getConnection().createStatement();
}
}
서로 다른 스 레 드 가 TopicDao 를 사용 할 때 connThreadLocal. get () 이 null 인지 여 부 를 판단 합 니 다. null 이 라면 현재 스 레 드 에 대응 하 는 Connection 대상 이 없다 는 것 을 설명 합 니 다. 이 때 Connection 대상 을 만 들 고 로 컬 스 레 드 변수 에 추가 합 니 다.null 이 아니라면 현재 스 레 드 가 Connection 대상 을 가지 고 있 음 을 설명 하고 직접 사용 하면 됩 니 다.이렇게 하면 서로 다른 스 레 드 는 스 레 드 와 관련 된 Connection 을 사용 하고 다른 스 레 드 의 Connection 을 사용 하지 않도록 보장 합 니 다.그래서 이 TopicDao 는 singleton 공유 가 가능 하 다.
물론 이 예 자체 가 거 칠 기 때문에 Connection 의 ThreadLocal 을 DAO 에 직접 두 면 이 DAO 의 여러 가지 방법 으로 Connection 을 공유 할 수 있 을 때 스 레 드 보안 문제 가 발생 하지 않 지만 다른 DAO 와 같은 Connection 을 공유 할 수 없습니다. 같은 사무 에서 다 DAO 가 같은 Connection 을 공유 하려 면 같은 외부 클래스 에서 ThreadLocal 을 사용 하여 Connection 을 저장 해 야 합 니 다.
작은 매듭
ThreadLocal 은 스 레 드 안전 문 제 를 해결 하 는 좋 은 사고 입 니 다. 모든 스 레 드 에 독립 된 변수 사본 을 제공 하여 변수 가 동시에 방문 하 는 충돌 문 제 를 해결 합 니 다.많은 상황 에서 ThreadLocal 은 synchronized 동기 화 체 제 를 직접 사용 하여 스 레 드 안전 문 제 를 해결 하 는 것 보다 더욱 간단 하고 편리 하 며 결과 프로그램 은 더욱 높 은 동시성 을 가진다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.