자바 자물쇠의 자물쇠 상세 정보

6225 단어 Java자물쇠
자물쇠는 공유 데이터를 병발하고 일치성을 확보하는 도구로 JAVA 플랫폼에서 여러 가지 실현이 있다(예를 들어synchronized와ReentrantLock 등).이미 작성된 자물쇠는 우리의 개발에 편의를 제공했지만 자물쇠의 구체적인 성질과 유형은 거의 언급되지 않았다.이 시리즈는 JAVA에서 흔히 볼 수 있는 자물쇠 이름과 특성을 분석하여 여러분의 궁금증을 풀어드리겠습니다.
1. 자전거 자물쇠
자전거 자물쇠는 현재 라인이 끊임없이 순환 체내에서 실행되도록 하는 것으로 순환의 조건이 다른 라인이 바뀔 때 임계 구역에 들어갈 수 있다.아래와 같다

public class SpinLock {

  private AtomicReference<Thread> sign =new AtomicReference<>();

  public void lock(){
    Thread current = Thread.currentThread();
    while(!sign .compareAndSet(null, current)){
    }
  }

  public void unlock (){
    Thread current = Thread.currentThread();
    sign .compareAndSet(current, null);
  }
}

CAS 원자 조작을 사용하여lock 함수는 owner를 현재 라인으로 설정하고 원래의 값이 비어 있음을 예측합니다.unlock 함수는 owner를null로 설정하고 예측값은 현재 라인입니다.
두 번째 스레드가 lock 동작을 호출할 때 owner 값이 비어 있지 않기 때문에 순환이 계속 실행됩니다. 첫 번째 스레드가 unlock 함수를 호출해서 owner를null로 설정해야 두 번째 스레드가 임계 구역에 들어갈 수 있습니다.
자전거 자물쇠는 현재 라인을 끊임없이 순환체로 실행하고 라인 상태를 바꾸지 않기 때문에 응답 속도가 더욱 빠르다.그러나 스레드 수가 끊임없이 증가할 때 성능이 현저히 떨어진다. 왜냐하면 모든 스레드가 실행되어야 하기 때문에 CPU 시간을 차지하기 때문이다.만약 라인 경쟁이 치열하지 않고 잠긴 시간대를 유지한다면.자전거 자물쇠를 사용하기에 적합하다.
주: 이 예는 비공평한 자물쇠입니다. 자물쇠를 획득하는 선후 순서는 락에 들어가는 선후 순서에 따라 진행되지 않습니다.
2. 자물쇠의 다른 종류
위에서 언급한 바와 같이 자전거 자물쇠는 자전거 자물쇠에서 세 가지 흔히 볼 수 있는 자물쇠 형식이 있다. 그것이 바로 TicketLock, CLHlock과 MCSlock이다.
Ticket 자물쇠는 주로 방문 순서의 문제를 해결하고 주요 문제는 다중 핵 cpu에 있다.

package com.alipay.titan.dcc.dal.entity;

import java.util.concurrent.atomic.AtomicInteger;

public class TicketLock {
    private AtomicInteger                     serviceNum = new AtomicInteger();
    private AtomicInteger                     ticketNum  = new AtomicInteger();
    private static final ThreadLocal<Integer> LOCAL      = new ThreadLocal<Integer>();

    public void lock() {
        int myticket = ticketNum.getAndIncrement();
        LOCAL.set(myticket);
        while (myticket != serviceNum.get()) {
        }

    }

    public void unlock() {
        int myticket = LOCAL.get();
        serviceNum.compareAndSet(myticket, myticket + 1);
    }
}

매번 서비스Num 서비스 번호를 조회해서 성능에 영향을 줍니다. (메인 메모리에서 읽고 다른 cpu 수정을 막아야 합니다.)
CLHLock과 MCSLock은 두 가지 유형이 비슷한 공평한 자물쇠로 체인 테이블 형식으로 정렬된다.

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class CLHLock {
    public static class CLHNode {
        private volatile boolean isLocked = true;
    }

    @SuppressWarnings("unused")
    private volatile CLHNode                                           tail;
    private static final ThreadLocal<CLHNode>                          LOCAL   = new ThreadLocal<CLHNode>();
    private static final AtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(CLHLock.class,
                                                                                   CLHNode.class, "tail");

    public void lock() {
        CLHNode node = new CLHNode();
        LOCAL.set(node);
        CLHNode preNode = UPDATER.getAndSet(this, node);
        if (preNode != null) {
            while (preNode.isLocked) {
            }
            preNode = null;
            LOCAL.set(node);
        }
    }

    public void unlock() {
        CLHNode node = LOCAL.get();
        if (!UPDATER.compareAndSet(this, node, null)) {
            node.isLocked = false;
        }
        node = null;
    }
}

CLHlock은 NUMA 아키텍처에서 사용할 수 없는 쿼리 선행 변수입니다. (이 아키텍처에서는 각 스레드가 서로 다른 물리적 메모리 영역에 분포되어 있습니다.)
MCSLock은 로컬 변수의 노드를 순환합니다.CLHlock 문제가 없습니다.

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class MCSLock {
    public static class MCSNode {
        volatile MCSNode next;
        volatile boolean isLocked = true;
    }

    private static final ThreadLocal<MCSNode>                          NODE    = new ThreadLocal<MCSNode>();
    @SuppressWarnings("unused")
    private volatile MCSNode                                           queue;
    private static final AtomicReferenceFieldUpdater<MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(MCSLock.class,
                                                                                   MCSNode.class, "queue");

    public void lock() {
        MCSNode currentNode = new MCSNode();
        NODE.set(currentNode);
        MCSNode preNode = UPDATER.getAndSet(this, currentNode);
        if (preNode != null) {
            preNode.next = currentNode;
            while (currentNode.isLocked) {

            }
        }
    }

    public void unlock() {
        MCSNode currentNode = NODE.get();
        if (currentNode.next == null) {
            if (UPDATER.compareAndSet(this, currentNode, null)) {

            } else {
                while (currentNode.next == null) {
                }
            }
        } else {
            currentNode.next.isLocked = false;
            currentNode.next = null;
        }
    }
}

코드상 CLH는 MCS보다 간단합니다.
CLH의 대기열은 암시적인 대기열로 실제 후계 결점 속성이 없습니다.
MCS의 대기열은 실제 후계 결점 속성이 있는 현식 대기열입니다.
JUC ReentrantLock의 기본 내부에 사용되는 자물쇠는 CLH 자물쇠입니다. (개선된 점이 많습니다. 자전거 자물쇠를 차단 자물쇠로 바꾸는 등등)
(전문 끝)

좋은 웹페이지 즐겨찾기