자바 스 레 드 폐쇄 스 택 폐쇄 및 ThreadLocal

스 레 드 폐쇄
다 중 스 레 드 환경 에서 우 리 는 자주 자 물 쇠 를 사용 하여 스 레 드 의 안전 을 확보 하지만 모든 스 레 드 에 사용 해 야 할 자원 에 자 물 쇠 를 사용 하면 프로그램 이 실행 하 는 효율 에 영향 을 받 을 수 있 습 니 다.이 럴 때 이런 자원 을 스 레 드 폐쇄 형식 으로 바 꿀 수 있 습 니 다.
1.창고 폐쇄
스 택 폐쇄 란 부분 변 수 를 사용 하여 자원 을 저장 하 는 것 입 니 다.우 리 는 부분 변 수 는 메모리 에 가상 컴퓨터 스 택 에 저장 되 고 스 택 은 모든 스 레 드 가 개인 적 으로 독립 되 어 있 기 때문에 스 레 드 의 안전 을 확보 할 수 있 습 니 다.
2、ThreadLocal
우선 ThreadLocal 과 스 레 드 Thread 의 관계 도 를 봅 시다.

ThreadLocal 의 동작 을 다시 보 세 요.get 을 예 로 들 면

public T get() {
    //     
    Thread t = Thread.currentThread();
   //        threadLocalMap,     map  
    ThreadLocalMap map = getMap(t);
    if (map != null) {
      //     ThreadLocal Key   Entry,             
      ThreadLocalMap.Entry e = map.getEntry(this);
      if (e != null) {
        @SuppressWarnings("unchecked")
        T result = (T)e.value;
        return result;
      }
    }
    //    null     
    return setInitialValue();
  }
위의 get 방법의 소스 코드 에서 보 듯 이 threadLocal.get()방법 을 호출 할 때 threadLocal 은 현재 스 레 드 에서 ThreadLocalMap 에서 threadLocal 자 체 를 key 로 대응 하 는 entry 를 가 져 왔 습 니 다.이 getEntry 방법 에서 메모리 누 출 처 리 를 했 습 니 다.대략 처리 순 서 는 threadLocal 에 대응 하 는 Entry 가 null 이면..이 entry 의 value 를 null 이 고 map 에서 thread Local 은 아래 표 시 된 null 에 대응 합 니 다.null 이 아니라면 되 돌려 줍 니 다.그렇지 않 으 면 기본 값 방법 setInitialValue()를 호출 합 니 다.

private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
      map.set(this, value);
    else
      createMap(t, value);
    return value;
  }

 //   null  
 protected T initialValue() {
    return null;
 }
setInitialValue()방법의 논 리 는 비교적 간단 하 다.여 기 는 군말 이 많 지 않다.주의해 야 할 것 은 안에서 호출 된 initialValue()는 아무런 실현 도 없 기 때문에 우 리 는 threadLocal 을 사용 할 때 보통 이 방법 을 다시 쓰 는 것 을 선택한다.

 //   main    ,   static  ,   threadLocal     ,        ,            
 public static ThreadLocal<String> threadLocal = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
      return "init string from initialValue method";
    }
  };

  public static void main(String[] args) throws InterruptedException {
    //    value    get
    System.err.println("invoke get before any set:" + threadLocal.get());
    threadLocal.set("test");
    System.err.println("before thread start : " + threadLocal.get());
    new Thread(() -> {
      //     threadLocal     
      threadLocal.set("test in thread");
      System.err.println("In thread[" + Thread.currentThread().getName() + "] threadLocal value : " + threadLocal.get());
    }).start();
    TimeUnit.SECONDS.sleep(1);
    //   threadLocal  value       
    System.err.println("after thread value : " + threadLocal.get());
  }  

이 애플 릿 과 위의 그림 을 결합 하면 threadLocal 에 대해 대충 이해 할 수 있 습 니 다.다른 방법,예 를 들 어 set,remove 등 방법 은 모두 대동소이 하 므 로 그림 과 결합 하여 소스 코드 를 볼 수 있 으 며 여 기 는 더 이상 군말 하지 않 습 니 다.
메모리 누 출 에 관 한 문제
1.thread Local 의 get,set,remove 방법 에서 발생 할 수 있 는 메모리 누 출 을 모두 처 리 했 습 니 다.논리 적 으로 도 entry 가 null 이면 value 를 null 로 설정 하고 map 에 대응 하 는 아래 표 시 를 null 로 참조 합 니 다.
2.threadLocal 에서 이 대상 의 누설 에 있어 약 한 인용 방식 으로 이 루어 집 니 다.위의 그림 에서 저 는 약 한 인용 을 점선 으로 표 시 했 습 니 다.약 한 인용 은 JVM 에서 쓰레기 를 회수 할 때 이 인용 은 회수 된다 는 뜻 입 니 다(메모리 가 충분 하 든 그렇지 않 든).강 한 인용 을 사용 하고 스 택 의 인용 이 사 라 졌 다 면 스 레 드 가 끝 날 때 까지 이 thread Local 대상 은 회수 되 지 않 고 접근 할 수 없습니다.즉,메모리 누 출 을 초래 하 는 것 입 니 다.
3.자바 네 가지 인용 에 대한 요약
위 에서 ThreadLocal 에서 약 한 인용 을 언급 했 습 니 다.자바 의 네 가지 인용 도 간단하게 말씀 드 리 겠 습 니 다.
4.567917.강 인용:new 가 나 온 대상 을 말 하 는데 보통 특별히 밝 히 지 않 은 대상 은 모두 강 인용 이다.이런 대상 은 GCroots 가 그것 을 찾 지 못 할 때 만 회수 된다
  • 소프트 참조(SoftReference 의 하위 클래스):GC 이후 메모리 가 부족 한 경우 이 참조 대상 만 회수 합 니 다
  • 약 인용(Weak Reference 의 하위 클래스):GC 에 서 는 이 인용 대상 만 회수 합 니 다(메모리 가 부족 하 든 그렇지 않 든)
  • 가상 인용(Phantom Reference 하위 클래스):특별한 기능 이 없습니다.추적 문자 와 유사 합 니 다.인용 대기 열 에 맞 춰 대상 이 언제 회수 되 었 는 지 기록 합 니 다.(실제로 이 네 가지 인용 은 인용 대기 열 에 맞 춰 사용 할 수 있 습 니 다.구조 방법 에 관련 된 인용 대기 열 을 입력 하면 됩 니 다.대상 이 finalize 방법 을 호출 할 때 대기 열 에 기 록 됩 니 다)
  • 이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기