ThreadLocal 원리 및 사용

6592 단어 java&javaweb
threadLocal 구현 에 대한 읽 기
사용 방식 및 Set 부분 이해,생 성 포함
 ThreadLocal threadLocal = new ThreadLocal<>();
   threadLocal.set(1);

1.thread Local 이라는 저장 방식 은 내부 에 하나의 인용 만 저장 할 수 있 습 니 다.(인용 은 용 기 를 가리 킬 수 있 습 니 다.예 를 들 어 map 또는 integer 와 같은 단일)2.thread Local 의 내부 실현 은 현재 스 레 드 를 얻 은 다음 에 현재 스 레 드 에 저 장 된 스 레 드 map ThreadLocalMap 을 얻 는 것 입 니 다.
ThreadLocalMap 내부 구현
1.ThreadLocalMap 의 key 는 현재 실례 화 된 thread Local 의 주소 입 니 다.값 은 저 장 된 object 유형 2 입 니 다.map 내부 의 실현 은 16 으로 초기 화 되 고 확장 한도 값 은 16*0.75+1 의 enity 배열 3 입 니 다.enity 내 부 는 reference(참조)+object 의 형식 reference 는 key 이 고 object 는 값 입 니 다.
  public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

set 값 을 설정 할 때 현재 스 레 드 와 스 레 드 내부 에 저 장 된 ThreadLocalMap 형식의 map 를 가 져 오고 map 에 값 을 설정 합 니 다.현재 스 레 드 가 다른 thread Local 에 의 해 설정 되 지 않 았 다 면 map 는 초기 화 되 지 않 았 습 니 다.먼저 ThreadLocalMap 초기 화(hashMap 유사)를 진행 합 니 다.
 private void set(ThreadLocal> key, Object value) {
       ...
            for (Entry e = tab[i];  e != null; e = tab[i = nextIndex(i, len)]) {
                ThreadLocal> k = e.get();
                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

set 에 서 는 먼저 key.hashcode&15 의 위 치 를 계산 하여 현재 스 레 드 의 인용 을 배치 할 적당 한 위 치 를 꺼 냅 니 다.이 위치 에서 아래로 옮 겨 다 니 기 시작 합 니 다.값 이 비어 있 지 않 으 면 들 어가 서 검증 합 니 다.현재 enity 의 key==나의 key 라면 교체 값 이 현재 enity 가 비어 있 지 않 지만 enity 안의 인용 은 null 입 니 다.자원 이 방출 되 었 음 을 설명 합 니 다.replace StaleEntry 를 통 해 값 설정 작업 을 진행 합 니 다.마지막 으로 빈 노드 를 찾 으 면 새로운 entity 를 만 들 고 이 k+v 를 설치 하고 rehash 작업(확장)이 필요 한 지 판단 합 니 다.
private void replaceStaleEntry(ThreadLocal> key, Object value,
                                       int staleSlot) {
           ...
           //slotToExpunge =    staleSlot  ,         k null index
           ...
            for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null;  i = nextIndex(i, len)) {
                ThreadLocal> k = e.get();
                //     staleSlot    ,  k==key,      ,  key                 (slotToExpunge)
                if (k == key) {
                    e.value = value;
                    tab[i] = tab[staleSlot];
                    tab[staleSlot] = e;

                    //                     ,                 i   ,              
                    if (slotToExpunge == staleSlot)
                        slotToExpunge = i;
                    cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
                    return;
                }

                // If we didn't find stale entry on backward scan, the
                // first stale entry seen while scanning for key is the
                // first still present in the run.
                //       ,  slotToExpunge == staleSlot  ,  slotToExpunge     ,             ,k  null,    slotToExpunge    map.length
                if (k == null && slotToExpunge == staleSlot)
                    slotToExpunge = i;
            }

            //      ,        ,   ,               ,"   "   
            tab[staleSlot].value = null;
            tab[staleSlot] = new Entry(key, value);

            // If there are any other stale entries in run, expunge them
            //  slotToExpunge!=staleSlot,      staleSlot  (       ),    staleSlot  (     slotToExpunge = i   ),     ,     ,      ,               cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
            if (slotToExpunge != staleSlot)
                cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
        }
 private int expungeStaleEntry(int staleSlot) {
        
              //    
            tab[staleSlot].value = null;
            tab[staleSlot] = null;
            size--;
           
            //       ,        
            Entry e;            int i;
            for (i = nextIndex(staleSlot, len);     (e = tab[i]) != null;       i = nextIndex(i, len)) {
                ThreadLocal> k = e.get();
                if (k == null) {
                  ...
                 //    
                } else {
                    int h = k.threadLocalHashCode & (len - 1);
                    //    k hash    i,               ,       i
                    //    e     ,    hash    ,(       ,      ,    ,            ,       ,       (null  )
                    if (h != i) {
                        tab[i] = null;
                        // Unlike Knuth 6.4 Algorithm R, we must scan until
                        // null because multiple entries could have been stale.
                        while (tab[h] != null)
                            h = nextIndex(h, len);
                        tab[h] = e;
                    }
                }
            }
            //         null   
            return i;
        }
private boolean cleanSomeSlots(int i, int n) {
            boolean removed = false;
            Entry[] tab = table;
            int len = tab.length;
            do {
                i = nextIndex(i, len);
                Entry e = tab[i];
                if (e != null && e.get() == null) {
                    n = len;
                    removed = true;
                    i = expungeStaleEntry(i);
                }
            } while ( (n >>>= 1) != 0);
            return removed;
        }

cleansome Slots 는 방금 얻 은 맨 앞 에 있 는 홈 점 부터 아래로 옮 겨 다 니 며 폐 기 된 인용 만 있 으 면 제거 하고 그 과정 에서 다시 교정 합 니 다.i=expunge StaleEntry 를 몇 번 더 교정 하여 폐 기 된 인용 이 없 는 존 재 를 확보 한 다음 에 상부 로 돌아 갑 니 다.reove 데이터 가 있 는 지 여 부 를 확인 합 니 다.
또 다른 문 제 는 메모리 유출 이 왜 매번 제때에 clean Some Slots 를 사용 해 야 하 는 지 입 니 다.여기 서 스 레 드 는 대상 을 인용 하고 대상 이 속 한 threadlocal 은 이미 풀 려 났 기 때 문 입 니 다.그러면 이 대상 은 존재 하지 않 을 것 입 니 다.그러나 제때에 풀 려 나 지 않 았 습 니 다.
get 논리
get 논리 가 간단 합 니 다.코드 를 붙 이지 않 습 니 다.주로 get 일 때 map 가 존재 하면 map 에서 찾 고 찾 으 면 되 돌려 줍 니 다.찾 는 과정 에서 폐 기 된 홈 점 이 발견 되면 청 소 를 하고 찾 지 못 하면 null 로 돌아 갑 니 다.map 가 존재 하지 않 으 면 기본 값 null 을 map 에 설정 하고 기본 값 initialValue 로 돌아 가 는 방법 은 proctected 입 니 다.복사 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기