자바 병발 J.U.C 의 AQS:CLH 동기 화 대기 열

CLH 동기 화 대기 열 은 FIFO 양 방향 대기 열 입 니 다.AQS 는 동기 화 상 태 를 관리 하 는 데 의존 합 니 다.현재 스 레 드 가 동기 화 상 태 를 가 져 오 는 데 실 패 했 을 때 AQS 는 현재 스 레 드 가 대기 상태 등 정 보 를 하나의 노드(Node)로 구성 하고 CLH 동기 화 대기 열 에 추가 합 니 다.또한 현재 스 레 드 를 차단 합 니 다.동기 화 상태 가 풀 릴 때 첫 번 째 노드 를 깨 웁 니 다(공동 잠 금).동기 화 상 태 를 다시 시도 합 니 다.
CLH 동기 화 대기 열 에서 한 노드 는 하나의 스 레 드 를 표시 합 니 다.스 레 드 의 참조(thread),상태(wait Status),전구 노드(prev),후계 노드(next)를 저장 하고 있 습 니 다.그 정 의 는 다음 과 같 습 니 다.

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;

 /**
 *         ,       Condition ,      Condition   signal() ,                   ,           
 */
 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;
 }

 Node() {
 }

 Node(Thread thread, Node mode) {
 this.nextWaiter = mode;
 this.thread = thread;
 }

 Node(Thread thread, int waitStatus) {
 this.waitStatus = waitStatus;
 this.thread = thread;
 }
}
CLH 동기 화 대기 열 구성 도 는 다음 과 같 습 니 다.

열거 하 다
데이터 구 조 를 배 운 우 리 는 CLH 대기 열 에 들 어 가 는 것 이 더 간단 하 다.tail 이 새로운 노드,새로운 노드 를 가리 키 는 prev 가 현재 의 마지막 노드 를 가리 키 고 현재 의 마지막 노드 의 next 는 현재 노드 를 가리킨다.코드 는 addWaiter(Node node)방법 을 볼 수 있 습 니 다.

 private Node addWaiter(Node mode) {
 //  Node
 Node node = new Node(Thread.currentThread(), mode);
 //         
 Node pred = tail;
 if (pred != null) {
 node.prev = pred;
 //CAS     
 if (compareAndSetTail(pred, node)) {
 pred.next = node;
 return node;
 }
 }
 //    
 enq(node);
 return node;
 }
addWaiter(Node node)는 먼저 빠 른 시 도 를 통 해 끝 노드 를 설정 하고 실패 하면 enq(Node node)방법 으로 끝 노드 를 설정 합 니 다.

 private Node enq(final Node node) {
 //    ,      
 for (;;) {
 Node t = tail;
 //tail   ,      
 if (t == null) {
 if (compareAndSetHead(new Node()))
 tail = head;
 } else {
 //      
 node.prev = t;
 if (compareAndSetTail(t, node)) {
 t.next = node;
 return t;
 }
 }
 }
 }
위의 코드 에서 두 가지 방법 은 모두 하나의 CAS 방법 인 compare AndSetTail(Node expect,Node update)을 통 해 끝 노드 를 설정 하 는데 이 방법 은 노드 가 안전하게 추 가 된 것 을 확보 할 수 있다.enq(Node node)방법 에서 AQS 는'죽은 순환'방식 으로 노드 를 정확하게 추가 할 수 있 도록 합 니 다.성공 적 으로 추가 한 후에 야 현재 스 레 드 가 이 방법 에서 돌아 올 수 있 습 니 다.그렇지 않 으 면 계속 실 행 될 것 입 니 다.
프로 세 스 그림 은 다음 과 같 습 니 다.

열거 하 다
CLH 동기 화 대기 열 은 FIFO 를 따 릅 니 다.첫 번 째 노드 의 스 레 드 가 동기 화 상 태 를 방출 한 후에 그의 후계 노드(next)를 깨 울 것 입 니 다.그리고 후계 노드 는 동기 화 상 태 를 성공 적 으로 가 져 올 때 자신 을 첫 번 째 노드 로 설정 합 니 다.이 과정 은 매우 간단 합 니 다.head 는 이 노드 를 실행 하고 원래 노드 의 next 와 현재 노드 의 prev 를 끊 으 면 됩 니 다.이 과정 에서 CAS 를 사용 하지 않 아 도 됩 니 다.하나의 스 레 드 만 동기 화 상 태 를 성공 적 으로 얻 을 수 있 기 때 문 입 니 다.프로 세 스 그림 은 다음 과 같 습 니 다.

이상 은 본문의 전체 내용 입 니 다.여러분 의 학습 에 도움 이 되 기 를 바 랍 니 다.여러분 도 저 희 를 많이 지지 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기