[실전 자바 고 병발 프로 그래 밍 7]스 레 드 간 에 서로 돕 기--SynchronousQueue 의 실현
내 가 이 절 에서 그것 을 소개 하려 고 하 는 이상 SynchronousQueue 는 예 를 들 어 잠 금 이 없 는 조작 과 관 계 를 끊 을 수 없다.실제로 SynchronousQueue 내부 에서 도 자물쇠 없 는 도 구 를 대량으로 사용 하고 있 습 니 다.
SynchronousQueue 에 있어 서 put()와 take()두 기능 이 전혀 다른 조작 을 하나의 공 통 된 방법 인 Transferer.transfer()로 추상 화 합 니 다.말 그대로 데이터 전달 이라는 뜻 이다.전체 서명 은 다음 과 같 습 니 다.
Object transfer(Object e, boolean timed, long nanos)
매개 변수 e 가 비어 있 지 않 을 때 현재 작업 이 한 소비자 에 게 전달 되 는 것 을 나타 내 고 비어 있 으 면 현재 작업 에 데 이 터 를 요청 해 야 한 다 는 것 을 나타 낸다.timed 매개 변 수 는 timeout 시간 이 존재 하 는 지 여 부 를 결정 합 니 다.nanos 는 timeout 의 시간 을 결정 합 니 다.반환 값 이 비어 있 지 않 으 면 데이터 및 수락 또는 정상 제공 을 표시 하고 비어 있 으 면 실패(시간 초과 또는 중단)를 표시 합 니 다.
SynchronousQueue 내부 에서 스 레 드 대기 열 을 유지 합 니 다.대기 열 에 대기 스 레 드 와 관련 된 데 이 터 를 저장 합 니 다.예 를 들 어 생산자 가 데 이 터 를 SynchronousQueue 에 넣 을 때 소비자 가 받 아들 이지 않 으 면 데이터 자체 와 스 레 드 대상 이 대기 열 에 포장 되 어 기 다 립 니 다(SynchronousQueue 용적 이 0 이기 때문에 정상적으로 넣 을 수 있 는 데이터 가 없습니다).
Transferer.transfer()함수 의 실현 은 SynchronousQueue 의 핵심 으로 크게 세 단계 로 나 뉜 다.
1.대기 열 이 비어 있 거나 대기 열 에 있 는 노드 의 유형 이 이번 작업 과 일치 하면 현재 작업 을 대기 열 에 눌 러 대기 합 니 다.예 를 들 어 대기 열 에 서 는 읽 기 스 레 드 가 기다 리 고 이번 작업 도 읽 기 때문에 이 두 개의 읽 기 를 기 다 려 야 합 니 다.대기 열 에 들 어 가 는 스 레 드 가 걸 릴 수 있 습 니 다.'일치'동작 을 기다 리 고 있 습 니 다.
2.대기 열 에 있 는 요소 와 이번 작업 이 서로 보완 된다 면(예 를 들 어 대기 동작 은 읽 기 이 고 이번 작업 은 쓰기)'완료'상태의 노드 를 삽입 하고 대기 노드 에'일치'하도록 합 니 다.이 어 이 두 노드 를 팝 업 하고 해당 하 는 두 스 레 드 를 계속 실행 합 니 다.
3.스 레 드 가 대기 행렬 의 노드 를 발견 하면'완성'노드 입 니 다.그럼 이 노드 가 임 무 를 완성 하도록 도와 주세요.그 절차 와 절차 2 는 일치한다.
STEP 1 의 실현 은 다음 과 같다(코드 참조 JDK 7u 60).
SNode h = head;
if (h == null || h.mode == mode) { // ,
if (timed && nanos <= 0) { //
if (h != null && h.isCancelled())
casHead(h, h.next); //
else
return null;
} else if (casHead(h, s = snode(s, e, h, mode))) {
SNode m = awaitFulfill(s, timed, nanos); // ,
if (m == s) { //
clean(s);
return null;
}
if ((h = head) != null && h.next == s)
casHead(h, s.next); // s fulfiller
return (mode == REQUEST) ? m.item : s.item;
}
}
위 코드 에서 첫 번 째 줄 SNode 는 대기 열의 노드 를 표시 합 니 다.내부 에 현재 스 레 드,next 노드,일치 하 는 노드,데이터 내용 등 정 보 를 밀봉 했다.두 번 째 줄 은 현재 대기 열 이 비어 있 거나 대기 열 에 있 는 요소 의 패턴 이 이번 작업 과 같다 고 판단 합 니 다(예 를 들 어 읽 기 동작 이 라면 모두 기 다 려 야 합 니 다).여덟 번 째 줄 은 새로운 노드 를 만 들 고 대기 열 머리 에 두 면 이 노드 는 현재 스 레 드 를 대표 합 니 다.입단 에 성공 하면 9 번 째 줄 await Fulfill()함 수 를 실행 합 니 다.이 함 수 는 자전 대기 하고 최종 적 으로 현재 스 레 드 를 걸 것 입 니 다.그 에 대응 하 는 조작 이 생 길 때 까지 깨 워 라.스 레 드 가 깨 어 난 후(데 이 터 를 읽 었 거나 자신 이 만 든 데 이 터 를 다른 스 레 드 에서 읽 었 음 을 표시 합 니 다)14~15 줄 에서 해당 하 는 스 레 드 가 두 머리 노드 의 출하 작업 을 완성 하 는 데 도움 을 주 려 고 시도 합 니 다(이것 은 우정 도움 일 뿐 입 니 다).마지막 으로 읽 거나 기록 한 데이터(16 줄)를 되 돌려 줍 니 다.
단계 2 의 실현 은 다음 과 같다.
} else if (!isFulfilling(h.mode)) { // fulfill
if (h.isCancelled()) //
casHead(h, h.next); //
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
for (;;) { // (match)
SNode m = s.next; // m s (match)
if (m == null) { //
casHead(s, null); // fulfill
s = null; //
break; //
}
SNode mn = m.next;
if (m.tryMatch(s)) {
casHead(s, mn); // s m
return (mode == REQUEST) ? m.item : s.item;
} else // match
s.casNext(m, mn); //
}
}
}
상기 코드 에서 먼저 머리 노드 가 fulfull 모드 에 있 는 지 판단 합 니 다.그렇다면,3 단계 로 들 어가 야 한다.그렇지 않 으 면 자신 이 대응 하 는 fulfilly 스 레 드 를 시도 합 니 다.네 번 째 줄 은 SNode 요 소 를 생 성하 여 fulfilly 모드 로 설정 하고 대기 열 머리 에 눌 러 줍 니 다.이 어 m(원본 대기 열 머리)를 s 의 일치 노드(13 줄)로 설정 합 니 다.이 try Match()작업 은 대기 스 레 드 를 활성화 시 키 고 m 를 그 스 레 드 에 전달 합 니 다.설정 이 성공 하면 데이터 배달 이 완료 되 었 음 을 나타 내 고 s 와 m 두 노드 를 팝 업 하면 됩 니 다(14 줄).try Match()가 실패 하면 다른 스 레 드 가 작업 을 마 쳤 다 는 뜻 입 니 다.m 노드 를 간단하게 삭제 하면 됩 니 다(17 줄).이 노드 의 데이터 가 배달 되 었 기 때문에 다시 처리 할 필요 가 없습니다.그리고 5 줄 의 순환 체 로 다시 이동 하여 다음 대기 스 레 드 의 일치 와 데이터 배달 을 진행 합 니 다.대기 열 에서 스 레 드 를 기다 리 지 않 을 때 까지.
STEP 3:스 레 드 가 실 행 될 때 머리 요소 가 fulfull 모드 인 것 을 발견 하면 이 fulfull 노드 가 빨리 실 행 될 수 있 도록 도와 줄 것 입 니 다.
} else { // fulfiller
SNode m =h.next; // m h match
if (m ==null) //
casHead(h,null); // fulfill
else {
SNode mn =m.next;
if(m.tryMatch(h)) // match
casHead(h, mn); // h m
else // match
h.casNext(m,mn); //
}
}
상기 코드 의 집행 원리 와 절차 2 는 완전히 일치한다.유일한 차이 점 은 절차 3 이 되 돌아 오지 않 는 다 는 것 이다.절차 3 이 진행 하 는 작업 은 다른 스 레 드 가 가능 한 한 빨리 데 이 터 를 배달 하도록 도와 주 는 것 이기 때문이다.자신 이 해당 하 는 조작 을 완성 하지 못 했 기 때문에 스 레 드 가 3 단계 에 들 어간 후에 다시 큰 순환 체(코드 에 제시 되 지 않 았 음)에 들 어가 1 단계 부터 조건 과 배달 데 이 터 를 다시 판단 한다.
전체 데 이 터 를 배달 하 는 과정 에서 볼 수 있 듯 이 SynchronousQueue 에서 작업 에 참여 하 는 모든 스 레 드 는 경쟁 자원 의 관계 만 이 아니다.더 중요 한 것 은 서로 돕 는 것 이다.하나의 스 레 드 내부 에 서 는 다른 스 레 드 가 작업 을 완성 하 는 데 도움 이 될 수 있 습 니 다.이런 모델 은 배 고 픔 의 가능성 을 어느 정도 줄 이 고 시스템 전체의 병행 도 를 높 일 수 있다.
[실전 자바 고 병발 프로 그래 밍 1]자바 의 지침:Unsafe 류
[실전 자바 고 병발 프로 그래 밍 2]잠 금 없 는 대상 참조:AtomicReference
[실전 자바 고 병발 프로 그래 밍 3]타임 스탬프 가 있 는 대상 참조:AtomicStamped Reference
[실전 자바 고 병발 프로 그래 밍 4]배열 도 잠 금 없 음:AtomicIntegerArray
[실전 자바 고 병발 프로 그래 밍 5]일반 변수 도 원자 조작 을 즐 길 수 있 도록 합 니 다.
[실전 자바 고 병발 프로 그래 밍 6]도전 무 잠 금 알고리즘
실전 자바 고 병발 프로 그래 밍
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.