멀티 스레딩 (6) - 뷰 잠금 일부의 성능을 향상시키기 위해

  잠금이 고도의 동시성 환경에서 동기화의 가장 일반적인 방법입니다, 치열한 경쟁은 프로그램의 성능 저하를 고정했다, 그래서 우리는 잠금 장치의 성능과 관련된 문제의 수뿐만 아니라 교착 상태를 피하는 등 일부주의 사항을 논의 할 필요가있다. 경쟁이 성능 저하 프로그램에 이르게의 잠금을 줄이기 위해, 당신은 그것을 성능을 향상시키기 위해 다음과 같은 제안을 사용할 수 있습니다.

  1. 잠금 대기 시간 감소

  그 과정에서 동시성 제어 잠금, 잠금 경합을 사용, 시간, 단일 스레드 잠금 시스템 성능이 직접적인 관계가 유지 응용 프로그램의 경우 경쟁의 정도의 이상, 더 강렬 후 잠금 장치의 잠금을 수용하는 스레드 . 예로서, 다음의 코드에서 :

공개  동기화  무효 syncMethod () { 
     othercode1 (); 
     mutexMethod (); 
     othercode2 (); 
}

  syncMethod () 메소드 만 mutexMethod () 메소드는 동기화를 위해 필요하다고 가정하고, othercode1 () 메소드 othercode2 () 메소드는 동기 제어를 할 필요가 없다. 이 값은 방법의 헤비급 방법이 있다면, 그것은 CPU, 높은 동시성에 시간이 오래 걸릴 것입니다, 동기화 전체 접근 방식은 스레드를 대기에 상당한 증가로 이어집니다. 스레드가 내부 잠금을 획득하는 방법에 진입하기 때문에, 잠금 만 모든 태스크의 실행 후에 릴리스 최적화 우리는 크게 시간 잠금 유지 실을 감소시키고 시스템 스루풋을 향상시킬 수 있도록 유일한 동기화가 필요하다 .

공개  공극 syncMethod2 () { 
     othercode1 (); 
     동기화 ( ) { 
          mutexMethod (); 
     } 
     othercode2 (); 
}

  2. 잠금 단위를 줄입니다

  또한 그에 따라서 복잡한 시스템의 용량을 증가 로크 충돌의 가능성을 줄여 좁은 로킹을 지칭한다. JDK의 일반적인 사용 시나리오는 ConcurrentHashMap의입니다,이 세그먼트의 HashMap의 여러 작은 내부지도가되었다, 기본값은 16 개 세그먼트입니다 (세그먼트) 세그먼트를했다.

  당신은) (ConcurrentHashMap의에게 새 항목이 아닌 전체 HashMap의 잠금을 증가하지만, 첫 번째 세그먼트에 저장해야하는에 따라 해시 코드 항목을 얻을, 다음 세그먼트를 고정하고 풋을 완료하는 방법을해야하는 경우 작동. 멀티 스레딩에서, 다수의 스레드가 동시에두면 () 동작은, 한 추가 항목이 같은 세그먼트에 저장되지 않기 때문에, 스레드 진정한 평행 할 수있다. 디폴트는 운 처리량을 크게 향상시키는 동시에, 삽입 실 (16)에 수용 될 16 개 세그먼트이다. () 연산 방법을 넣어 다음 코드 방법. 코드 5-6 라인 세그먼트에 대응하는 키 번호 J에 따라 수득하고, 주어진 세그먼트 내의 데이터를 삽입 한 다음 세그먼트들 구하여하기.

공용 V 넣어 (K 키 V 값) { 
     세그먼트 <K, V> S;
     경우 (값 == )
          던져  새로운 (NullPointerException가);
     INT의 해시 = 해시 (키);
     INT의 J = (해시 >>> segmentShift) segmentMask;
     경우 ((S = (세그먼트 <K, V>) UNSAFE.getObject           // 휘발성; 재확인 
          (세그먼트 (J << SSHIFT) + SBASE)) ==  ) //   ensureSegment에서 
         S = ensureSegment (j);
     반환 s.put을 (키, 해시 값, 거짓 );
}

  시스템이 많은 리소스를 소모 글로벌 잠금을 필요로하는 경우 그러나, 입자 크기를 감소시키는 것은 새로운 문제를 가져올 것이다. 예를 들어, 글로벌 정보 ConcurrentHashMap의를 얻기 위해, 우리는 성공적으로 구현되기 전에 모든 세그먼트에 대한 잠금을 획득해야합니다. 맵 크기 () 메소드 ConcurrentHashMap의 모든 유효 엔트리, 모든 서브 세그먼트에 정보 취득 로크를 획득 할 필요가 있으므로, 코드의 크기 ()를 다음과 같은 방법이 리턴되도록 :

공공  INT의 크기 () {
     // 정확한 수를 얻기 위해 여러 번 시도합니다. 연속 비동기 변경 테이블 실패하면 잠금을 사용합니다.
    최종 세그먼트 <K, V> [] = 세그먼트 은이 .segments,
     INT의 크기,
     부울 오버 플로우; 
      SUM;          // 
     = 0L 마지막;    // 의 수 
    INT 재시도 = -1; 
     은 try {
         에 대한 (;;) {
             IF (재시 ++ == RETRIES_BEFORE_LOCK) {
                  ( INT J = 0; J <segments.length; ++ J)
                    ensureSegment (J) .lock () // 모든 세그먼트가 잠금 
            } 
            SUM = 0L ; 
            크기 = 0 ; 
            오버플 = false로 ,
              ( INT , J <segments.length, J = 0 ++ J) { 
                세그먼트 <K , V> SEG = segmentAt (세그먼트, J),
                 IF (! = SEG 는 null ) { 
                    SUM + = seg.modCount // 통계 수
                     INT C = seg.count;
                     IF(c <0 || (크기 = + c) <0 ) 
                        오버플 = ; 
                } 
            } 
            경우 (합계 == 마지막)
                 체류 ; 
            마지막 = 합; 
        } 
    } 마지막 {
         경우 (재시> RETRIES_BEFORE_LOCK) {
              ( INT의 J = 0; J <segments.length; ++ j)를 
                segmentAt (세그먼트 J) .unlock (); //释放所有锁
        } 
    } 
    반환 오버 플로우? 에 Integer.MAX_VALUE : 크기;
}

  그 방법이 잠겨하려고합니다 실패하면 당신은) 위의 코드 크기 (에서 고정-합하는 최초의 시도를 볼 수 있습니다. 이 방법은 진정한 의미에서 시스템의 처리량을 개선하기 위해 잠금의 크기를 줄일 경우에만 비슷한 크기 () 메소드는 메소드 호출의 글로벌 정보 드물게 사용을 얻을 수 있습니다.

  3. 또는 읽기 분리 및 잠금 단독 잠금을 쓰기

  별도의 리드를 사용하는 ReadWriteLock하고 시스템의 성능을 향상시킬 수 잠금 물품이 실제로 입경 별도 판독을 줄이고 잠금 시스템 기능 분할 점이다 물품의 특별한 경우이다. 읽기 작업 자체가 데이터의 무결성과 일관성에 영향을 미치지 않습니다, 따라서 이론적으로, 동시에 여러 스레드간에 읽을 수 수 있기 때문에, 읽기 - 쓰기 잠금이 기능의 실현입니다. 그래서 읽고 효율적으로 시스템의 성능을 향상시킬 수보다 적은 경우를 동시 읽기 - 쓰기 잠금을 작성.

  4. 잠금 격리

  쓰기 잠금 아이디어가 더 분리 연장 잠겨 있습니다. 쓰기 읽기의 잠금과는 다른 기능, 잠금의 효과적인 분리의 쓰기 작업. 우리는 유사한 분리 아이디어를 사용하여 응용 프로그램의 기능을 기반으로 할 수 있습니다, 그것은 또한 독점 잠금을 분리 할 수있다. LinkedBlockingQueue를 구현은,리스트의 헤드의 작용 효과를 모두 ()을 가지고 넣어 ()는 각각의 큐와 증가 된 데이터로부터 데이터를 취득하는 기능을 달성하기 위해, 함수 큐 개의 변형이 있지만, 그러나리스트에 LinkedBlockingQueue 기초 연결리스트의 꼬리에 작용, 이론적으로, 두 사람은 충돌하지 않습니다. 단독 잠금을 사용하여, 어쩌면 방법은 진정한 동시성을 달성 할 수없는, 그들은 잠금 리소스를 해제하기 위해 서로 기다립니다. JDK는 각각 두 개의 자물쇠 ()로 받아 () 넣어 분리 하였다.

/ ** 잠금 테이크, 여론 조사 등이 보유 * / 
민간  최종 ReentrantLock와 takeLock = ) (ReentrantLock와; 

/ ** 대기를위한 대기 큐가 소요 * / 
민간  최종 상태는 NotEmpty = takeLock.newCondition를 (); 

/ ** 등을 넣어, 제공, 보유 잠금 * / 
민간  최종 ReentrantLock와 putLock = 새로운 ReentrantLock와 (); 

/ ** 풋을 대기위한 대기 큐 * / 
민간  최종 상태 notFull = putLock.newCondition ();

  TakeLock는 어쩌면 서로 독립적이 방법은, 잠금 어쩌면 방법을 사이에 경쟁이 만 () (소요 및 소요가 없다, (테이크에서 사용)와 () 메소드를 넣어 코드 및 putLock, 위의 정의 룸) 메소드를 넣어 ()와 takeLock 방법과 putLock 사이에 각각) (넣어함으로써 잠금 경합을 약화, 경쟁. 다음과 같은 방법을 구현 임) (취

공공 E의 포획은 () 가 발생 예외 : InterruptedException { 
    E X를, 
    INT C = -1 ;
     최종 AtomicInteger 카운트 = 다음은이 .count,
     최종 ReentrantLock와 = takeLock의 다음은이 ; .takeLock 
    takeLock.lockInterruptibly (); // 동시에 데이터를 가져 오는 두 개의 스레드가 가질 수 없습니다 
    시도를 {
         그동안 (count.get () == 0 데이터 없음중인 경우) {// 대기 
            )를 notEmpty.await (//는 (넣어 기다리는) 통지 동작 방법 
        } 
        X = 디큐을 (); // 첫 얻을 데이터 
        C = count.getAndDecrement (); // 숫자 원자 동작을 저장하고, 따라서 (넣어) 동시에 액세스 할 수
        IF . (C> 1 ) 
            notEmpty.signal (); // 동작의 다른 권취 () 메소드를 통지 
    } 최종적 { 
        takeLock.unlock (); // 분리 잠금 
    } 
    IF (C == 용량) 
        signalNotFull는 (); // 알림 넣어 () 작업, 자유 공간 기존의 
    반환 X; 
}

  다음을 달성하기 위해 () 메소드 입력 :

공개  공극 PUT (E E)이 발생 예외 : InterruptedException {
     IF (E ==  ) 드로  새로운 새 , NullPointerException이 () 
    INT C = -1 , 
    노드 <E> = 노드 새로운 신규 노드 (E)
     최종 ReentrantLock와 = putLock의 이 본 .putLock,
     파이널 = AtomicInteger의 COUNT 이 본 .count; 
    putLock.lockInterruptibly는 (); // 두 스레드가 동시에 넣을 수 () 방법 
    은 try {
         그동안 (count.get () == 용량) {// 큐가 가득
            notFull.await (); // 대기 
        } 
        인큐 (노드) // 데이터 삽입 
        C = count.getAndIncrement (). // C 변수 값 전에 1 씩 카운트 총 개수를 업데이트
         IF (.의 C + 1 < 용량) 
            notFull .signal (); // 다른 스레드에 통지 할 수있는 충분한 공간이 
    } 최종적 { 
        // 분리 잠금; putLock.unlock () 
    } 
    IF (C == 0 ) 
        signalNotEmpty (); // 성공 삽입 통지 찍은 후 () 메소드 데이터 가져 오기 
}

  잠금 조

  일반적으로, 여러 스레드 간의 효율적인 동시성을 보장하기 위해, 각 스레드는 즉시, 가능한 한 짧은 시간의 잠금을 자원의 사용 후 잠금을 해제하라는 메시지가 표시됩니다. 유일한 방법은 가능한 한 빨리 잠겨있는 다른 스레드에서 대기 작업을 수행 할 자원을 얻을 수 있지만, 동일한 논스톱 잠금 요청하는 경우, 동기화도 시스템 리소스를 소모 출시,하지만 성능 최적화에 도움이되지. 이를 위해 지속적인 요청 및 해제에 잠금 연속 동작의 일련의 얼굴에 가상 머신이, 그것은 잠금하여 잠금 동기화 요청의 수를 감소 쌍의 잠금 장치에서 작동하는 모든 통합 요청을 넣어 것입니다,이 작업이 호출됩니다 잠금 조.

  개발하는 동안, 우리는 각 루프가 잠금을 가지고 있기 때문에, 적절한 경우에 특히 내부 루프 잠금 요청을 조를 잠그고 잠금 응용 프로그램의 작동을 해제 할 수 있습니다, 사실은 완전히 불필요 밖에 고정 루프입니다 그것.

추천

출처www.cnblogs.com/wangyongwen/p/11257517.html