ThreadLocal 이해

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 동기 화 체 제 를 직접 사용 하여 스 레 드 안전 문 제 를 해결 하 는 것 보다 더욱 간단 하고 편리 하 며 결과 프로그램 은 더욱 높 은 동시성 을 가진다.

좋은 웹페이지 즐겨찾기