자바 병렬 시리즈 의 AbstractQueuedSynchronizer 소스 코드 분석(개요 분석)

자바 병행 프로 그래 밍 을 배 우려 면 자바.util.concurrent 라 는 가방 을 알 아야 합 니 다.이 가방 아래 에는 우리 가 자주 사용 하 는 병행 도구 류 가 많 습 니 다.예 를 들 어 ReentrantLock,Count Downlatch,Cyclic Barrier,Semaphore 등 이 있 습 니 다.이러한 유형의 밑바닥 실현 은 모두 AbstractQueued Synchronizer 와 같은 종류 에 의존 하 는데 이 를 통 해 이러한 중요성 을 알 수 있다.그래서 자바 병발 시리즈 글 에서 저 는 먼저 AbstractQueued Synchronizer 라 는 유형 을 분 석 했 습 니 다.이런 유형 이 비교적 중요 하고 코드 가 길 기 때문에 가능 한 한 투철 하 게 분석 하기 위해 저 는 네 편의 글 로 이런 유형 에 대해 비교적 완전한 소 개 를 하기 로 결 정 했 습 니 다.이 글 은 개요 로 서 주로 독자 들 로 하여 금 이런 유형 에 대해 초보적인 이 해 를 가지 게 하 는 것 이다.서술 이 간단 하기 위해 서 는 나중에 AQS 로 이런 종 류 를 대표 하 는 곳 도 있다.
1.AbstractQueued Synchronizer 이런 종 류 는 무엇 입 니까?
많은 독자 들 이 ReentrantLock 을 사용 해 야 한다 고 믿 지만 Abstract Queued Synchronizer 의 존 재 를 모른다.사실 ReentrantLock 은 내부 클래스 Sync 를 실 현 했 습 니 다.이 내부 클래스 는 AbstractQueued Synchronizer 를 계승 하고 모든 잠 금 체제 의 실현 은 Sync 내부 클래스 에 의존 합 니 다.또한 ReentrantLock 의 실현 은 AbstractQueued Synchronizer 류 에 의존 하 는 것 이 라 고 할 수 있 습 니 다.이와 유사 하 게 Count Downlatch,Cyclic Barrier,Semaphore 등 도 같은 방식 으로 자물쇠 에 대한 제 어 를 실현 한다.이 를 통 해 알 수 있 듯 이 Abstract Queued Synchronizer 는 이러한 종류의 초석 이다.그렇다면 AQS 내부 에서 무엇 을 이 루 었 기 때문에 이런 것들 은 모두 그것 에 의존 해 야 합 니까?이렇게 말 하면 AQS 는 이러한 유형 에 인 프 라 를 제공 했다.즉,암호 자 물 쇠 를 제공 했다.이런 유형 은 암호 자 물 쇠 를 가 진 후에 스스로 암호 자 물 쇠 를 설정 할 수 있 는 비밀 번 호 를 가진다.그 밖 에 AQS 는 줄 을 서 는 구역 을 제공 하고 스 레 드 교도 관 을 제공 했다.우 리 는 스 레 드 가 마치 원시 적 인 야만인 과 같다 는 것 을 알 고 있다.예 의 를 지 키 지 못 하고 좌충우돌 만 하기 때문에 한 걸음 한 걸음 줄 을 서서 언제 줄 을 서 야 하 는 지,어디로 줄 을 서 야 하 는 지,줄 을 서기 전에 무엇 을 해 야 하 는 지,줄 을 서서 무엇 을 해 야 하 는 지 알려 줘 야 한다.이러한 교화 작업 은 모두 AQS 가 당신 을 도와 완성 하 였 습 니 다.여기 서 교 화 된 라인 은 모두 매우 문명 하고 예의 바 르 며 원시 적 인 야만인 이 아 닙 니 다.그래서 앞으로 우 리 는 이런 문명 의 라인 과 만 나 기만 하면 됩 니 다.절대 원시 라인 과 너무 많은 접촉 을 하지 마 세 요!
2.왜 AbstractQueued Synchronizer 가 비밀번호 자 물 쇠 를 제공 했다 고 말 합 니까?

//        
private transient volatile Node head; 

//        
private transient volatile Node tail;

//    
private volatile int state;

//      
protected final int getState() {
 return state;
}

//      
protected final void setState(int newState) {
 state = newState;
}

// CAS        
protected final boolean compareAndSetState(int expect, int update) {
 return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
위의 코드 는 AQS 의 모든 구성원 변 수 를 보 여 줍 니 다.AQS 의 구성원 변 수 는 세 개 에 불과 합 니 다.동기 화 큐 헤드 노드 참조,동기 화 큐 끝 노드 참조 와 동기 화 상태 입 니 다.이 세 멤버 변 수 는 모두 volatile 키 워드 를 사용 하여 수식 되 었 습 니 다.이 는 여러 스 레 드 가 메모리 에 보 이 는 것 을 확보 합 니 다.전체 클래스 의 핵심 은 바로 이 동기 상태 입 니 다.동기 상 태 는 int 형의 변수 입 니 다.여러분 은 이 동기 상 태 를 암호 자물쇠 로 볼 수 있 습 니 다.그리고 방 안에서 잠 긴 암호 자물쇠 입 니 다.state 의 구체 적 인 값 은 암호 가 암호 자물쇠 의 개폐 를 제어 하 는 것 과 같 습 니 다.물론 이 자물쇠 의 비밀 번 호 는 각 하위 클래스 에 의 해 규정 된다.예 를 들 어 ReentrantLock 에서 state 는 0 은 자물쇠 가 열 려 있다 는 것 을 나타 내 고 state 는 0 보다 크 면 자물쇠 가 잠 겨 있다 는 것 을 나타 내 며 Semaphore 에서 state 는 0 보다 크 면 자물쇠 가 열 려 있다 는 것 을 나타 내 고 state 는 0 은 자물쇠 가 잠 겨 있다 는 것 을 나타 낸다.
3.AbstractQueued Synchronizer 의 대기 구역 은 어떻게 이 루어 집 니까?

AbstractQueued Synchronizer 내부 에 두 개의 줄 이 있 는데 하 나 는 동기 화 대기 열 이 고 하 나 는 조건 대기 열 입 니 다.위의 그림 에서 보 듯 이 동기 화 대기 열 은 하나 뿐 이 고 조건 부 대기 열 은 여러 개 있 을 수 있다.동기 화 대기 열의 결점 은 각각 앞 뒤 결점 의 인용 을 가지 고 있 으 며,조건 대기 열의 결점 은 후계 결점 을 가리 키 는 인용 만 있다.그림 에서 T 는 스 레 드 를 표시 합 니 다.모든 노드 에 스 레 드 가 포함 되 어 있 습 니 다.스 레 드 는 잠 금 을 가 져 오 는 데 실패 한 후에 동기 화 대기 열 에 들 어가 서 줄 을 서 야 합 니 다.조건 대기 열 에 들 어 가 려 면 이 스 레 드 는 잠 금 을 가 져 야 합 니 다.다음은 대열 의 모든 결점 의 구 조 를 살 펴 보 자.

//       
static final class Node {
 
 static final Node SHARED = new Node(); //              
 
 static final Node EXCLUSIVE = null; //              

 static final int CANCELLED = 1;  //             
 
 static final int SIGNAL = -1;  //             
 
 static final int CONDITION = -2;  //              
 
 static final int PROPAGATE = -3;  //             

 volatile int waitStatus; //           
 
 volatile Node prev;  //            

 volatile Node next;  //             

 volatile Thread thread; //           
 
 Node nextWaiter;   //            

 //             
 final boolean isShared() {
  return nextWaiter == SHARED;
 }

 //           
 final Node predecessor() throws NullPointerException {
  Node p = prev;
  if (p == null) {
   throw new NullPointerException();
  } else {
   return p;
  }
 }
 
 //   1
 Node() {}
 
 //   2,         
 Node(Thread thread, Node mode) {
  //          nextWaiter
  this.nextWaiter = mode;
  this.thread = thread;
 }
 
 //   3,          
 Node(Thread thread, int waitStatus) {
  this.waitStatus = waitStatus;
  this.thread = thread;
 }
}
Node 는 동기 화 대기 열과 조건 대기 열의 결점 을 대표 합 니 다.이것 은 AbstractQueuedSynchronizer 의 내부 클래스 입 니 다.Node 는 많은 속성 이 있 습 니 다.예 를 들 어 모드,대기 상태,동기 화 대기 열 에 있 는 중계 와 후계,그리고 조건 대기 열 에 있 는 후계 참조 등 이 있 습 니 다.동기 화 대기 열과 조건 대기 열 을 줄 서기 구역 으로 볼 수 있 고,각 노드 는 줄 서기 구역 의 좌석 으로 볼 수 있 으 며,라인 을 줄 서기 손님 으로 볼 수 있다.손님 이 처음 왔 을 때 먼저 문 을 두 드 리 고 자물쇠 가 열 렸 는 지 확인 합 니 다.자물쇠 가 열 리 지 않 으 면 줄 을 서서 번호 표를 받 고 자신 이 어떤 방식 으로 자 물 쇠 를 가지 고 싶 은 지 밝 히 고 마지막 으로 대열 의 끝 에 가서 줄 을 서 겠 습 니 다.
4 어떻게 독점 모델 과 공유 모델 을 이해 합 니까?
앞에서 말 했 듯 이 모든 손님 들 이 줄 을 서기 전에 번호 표를 받 고 자신 이 어떤 방식 으로 자 물 쇠 를 차지 하고 자 하 는 지 밝 히 며 자 물 쇠 를 차지 하 는 방식 은 독점 모델 과 공유 모델 로 나 뉜 다.그러면 독점 모델 과 공유 모델 을 어떻게 이해 할 것 인가?정말 좋 은 비 유 를 찾 을 수 없다.사람들 은 공중 화장실 을 연상 할 수 있다.독점 모델 의 사람 은 비교적 포악 하 다.아버 지 는 들 어 오지 않 거나 들 어 오 면 다른 사람 이 들 어 오지 못 하 게 하고 혼자 화장실 전 체 를 점용 한다.공유 모드 를 가 진 사람 은 그렇게 신경 을 쓰 지 않 습 니 다.이 화장실 이 이미 사용 할 수 있다 는 것 을 알 게 된 후에 스스로 들 어 오 는 것 도 아 닙 니 다.뒤에 있 는 사람 에 게 같이 사용 하 는 것 을 개의 치 않 는 다 고 열심히 물 어 봐 야 합 니 다.만약 에 뒤에 있 는 사람 이 같이 사용 하 는 것 을 개의 치 않 는 다 면 줄 을 서지 않 아 도 됩 니 다.물론 뒤에 있 는 사람 이 개의 치 않 는 다 면 대열 에 남아 계속 줄 을 서 야 합 니 다.
5 결점 의 대기 상 태 를 어떻게 이해 합 니까?
우 리 는 또한 모든 노드 에 하나의 대기 상태 가 있 는 것 을 보 았 다.이 대기 상 태 는 CANCELLED,SIGNAL,CONDITION,PROPAGATE 네 가지 상태 로 나 뉜 다.이 대기 상 태 를 좌석 옆 에 걸 려 있 는 간판 으로 보고 현재 좌석 에 있 는 사람의 대기 상 태 를 표시 할 수 있다.이 브랜드 의 상 태 는 스스로 수정 할 수 있 을 뿐만 아니 라 다른 사람 도 수정 할 수 있다.예 를 들 어 이 스 레 드 가 줄 을 서 는 과정 에서 포기 하려 고 하면 자신의 좌석 에 있 는 간판 을 CANCELLED 로 설정 하여 다른 사람들 이 보면 대기 열 을 정리 할 수 있다.또 다른 경 우 는 스 레 드 가 자리 에서 잠 들 기 전에 자신 이 늦잠 을 잘 까 봐 앞 자리 의 팻말 을 SIGNAL 로 바 꾸 는 경우 도 있다.모든 사람 이 대열 을 떠 나 기 전에 자신의 자리 로 돌아 가 한 번 씩 보기 때문이다.팻말 의 상태 가 SIGNAL 인 것 을 보면 다음 사람 을 깨 우 는 경우 도 있다.앞 자리 에 있 는 브랜드 가 SIGNAL 이 어야 현재 스 레 드 가 안심 하고 잘 수 있 습 니 다.CONDITION 상 태 는 이 스 레 드 가 조건 부 대기 열 에 줄 을 서 있 음 을 나타 내 며,PROPAGATE 상 태 는 뒤에 오 는 스 레 드 에 게 자 물 쇠 를 직접 가 져 올 수 있 음 을 알려 줍 니 다.이 상 태 는 공유 모드 에서 만 사용 되 며,뒤에 공유 모드 를 따로 말 할 때 만 설명 합 니 다.
6.결점 이 동기 화 대기 열 에 들 어 갈 때 어떤 조작 을 합 니까?

//      ,        
private Node enq(final Node node) {
 for (;;) {
  //           
  Node t = tail;
  //                   
  if (t == null) {
   //       
   if (compareAndSetHead(new Node())) {
    tail = head;
   }
  } else {
   //1.       
   node.prev = t;
   //2.          
   if (compareAndSetTail(t, node)) {
    //3.                
    t.next = node;
    //for       
    return t;
   }
  }
 }
}

입단 작업 은 고정 순환 을 사용 합 니 다.동기 화 대기 열 끝 에 노드 를 성공 적 으로 추가 해 야 되 돌아 갑 니 다.결 과 는 동기 화 대기 열 원래 의 끝 점 입 니 다.다음 그림 은 전체 조작 과정 을 보 여 준다.

독자 들 은 끝 점 을 추가 하 는 순 서 를 주의해 야 한다.세 단계 로 나 눌 수 있다.끝 점 을 가리 키 고 CAS 는 끝 점 을 바 꾸 고 낡은 끝 점 의 후계 가 현재 의 결점 을 가리킨다.동시 다발 환경 에서 이 세 단계 작업 이 반드시 완 료 될 수 있 는 것 은 아니 기 때문에 동기 화 대기 열 에서 취 소 된 모든 노드 를 비 우 는 작업 에서 취소 되 지 않 은 상태의 결점 을 찾기 위해 서 는 예전 부터 뒤로 옮 겨 다 니 는 것 이 아니 라 뒤에서 옮 겨 다 니 는 것 입 니 다.그리고 각 노드 가 대기 열 에 들 어 갈 때 대기 상 태 는 0 이 고 후계 노드 의 스 레 드 가 걸 려 야 할 때 만 앞 노드 의 대기 상 태 를 SIGNAL 로 바 꿉 니 다.
주의:상기 모든 분석 은 JDK 1.7 을 바탕 으로 버 전 간 에 차이 가 있 을 수 있 으 므 로 독자 들 은 주의해 야 합 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기