Java 동시성 프로그래밍을 배우려면 java.util.concurrent 패키지에 대해 배워야합니다. 이 패키지에서 재입국, 카운트 다운 레이트, 사이클리 바리어, 세마포어 등과 같은 많은 동시 도구 클래스가 있습니다. Java Concurrency 시리즈에서 먼저 AbstractQueuedSynchronizer 클래스를 분석했습니다. 이 클래스가 더 중요하고 코드가 비교적 길기 때문에 가능한 한 철저하게 분석하기 위해 4 개의 기사를 사용 하여이 클래스에 대해 비교적 완전한 소개를하기로 결정했습니다. 이 기사는 독자들 에게이 범주에 대한 예비 이해를 제공하기위한 요약 소개입니다. 나레이션의 단순성을 위해 일부 장소는 AQ를 사용하여 미래 에이 클래스를 대표 할 것입니다.
1. AbstractQueuedSynchronizer 클래스는 무엇입니까?
나는 많은 독자들이 ReintrantLock을 사용했다고 생각하지만 AbstractQueuedSynchronizer의 존재를 모릅니다. 실제로 ReintrantLock은 내부 클래스 동기화를 구현하여 AbstractQueuedSynchronizer를 상속합니다. 모든 잠금 메커니즘 구현은 동기화 내부 클래스에 의존합니다. 또한 ReintrantLock의 구현은 AbstractQueuedSynchronizer 클래스에 따라 다릅니다. 마찬가지로 CountdownLatch, Cyclicbarrier 및 Semaphore 클래스는 동일한 방법을 사용하여 자체 자물쇠 제어를 구현합니다. AbstractQueuedSynchronizer는이 클래스의 초석이라는 것을 알 수 있습니다. 따라서 AQS 내에서 정확히 구현되어 이러한 모든 클래스가 그것에 의존 할 수 있도록? AQS는 이러한 클래스에 인프라를 제공한다고 말할 수 있습니다. 즉, 비밀번호 잠금을 제공합니다. 이 클래스에 비밀번호 잠금이 있으면 비밀번호 잠금의 비밀번호를 자체적으로 설정할 수 있습니다. 또한 AQS는 큐 영역과 스레드 강사를 제공합니다. 우리는 실이 원시 야만인과 같다는 것을 알고 있습니다. 그들은 예의 바른 방법을 모릅니다. 그들은 단지 돌진 할 것이므로 단계별로 가르쳐주고, 대기열이 필요할 때, 대기열 장소, 대기하기 전에해야 할 일, 그리고 대기 후해야 할 일을 말해야합니다. 이 모든 교육 작업은 AQ에 의해 완료됩니다. 그것으로부터 교육을받은 실은 매우 문명화되고 예의 바르고 더 이상 원시적 인 야만인이 아닙니다. 따라서 미래에는 이러한 문명화 된 실을 다루면됩니다. 원래 스레드와 너무 접촉하지 마십시오!
2. AbstractQueuedSynchronizer가 암호 잠금을 제공하는 이유는 무엇입니까?
// 동기화 큐의 헤드 노드 개인 과도 휘발성 노드 헤드; // 동기화 큐의 꼬리 노드 비공개 과도 휘발성 노드 테일; // 개인 휘발성 int 상태; // 동기화 상태 get get synchronization state protected int getstate () {return state;} // set synchronization state protected final void setstate (int newstate) {newstate = newstate;} set intstate (int intetstate). {return unsafe.compareAndswapint (this, stateOffset, expling, update);}위의 코드에는 AQ의 모든 멤버 변수가 나와 있습니다. AQ에는 3 개의 멤버 변수, 즉 동기화 큐 헤드 노드 참조, 동기화 큐 테일 노드 참조 및 동기화 상태 만 있음을 알 수 있습니다. 세 가지 멤버 변수는 모두 휘발성 키워드로 수정되므로 여러 스레드가 메모리가 가시 가능합니다. 전체 클래스의 핵심은이 동기화 상태입니다. 동기화 상태가 실제로 int-type 변수임을 알 수 있습니다. 이 동기화 상태를 암호 잠금으로 간주 할 수 있으며 객실에서 잠겨있는 암호 잠금 장치이기도합니다. 상태의 특정 값은 비밀번호 잠금의 시작 및 종료를 제어하는 암호와 동일합니다. 물론,이 잠금의 비밀번호는 각 서브 클래스에 의해 결정됩니다. 예를 들어, ReintrantLock에서 State는 0과 동일하며, 잠금이 열려 있고, 0보다 큰 상태는 잠금이 잠겨 있음을 의미하고, 세마포어에서는 0보다 큰 상태는 잠금이 열려 있음을 의미하며 상태 0과 동일하게 유지되면 잠금이 잠금이 잠금되었음을 의미합니다.
3. AbstractQueuedSynchronizer의 대기열 영역은 어떻게 구현됩니까?
AbstractQueuedSynchronizer에는 실제로 두 개의 대기열 영역이 있으며, 하나는 동기 대기열이고 다른 하나는 조건부 대기열입니다. 위 그림에서 볼 수 있듯이 하나의 동기화 큐는 하나만 있으며 여러 조건 큐가있을 수 있습니다. 동기 큐의 노드는 각각 전면 및 후면 노드에 대한 참조를 유지하는 반면, 조건부 큐의 노드는 후속 노드에 대한 하나의 참조 만 가지고 있습니다. 그림에서 t는 스레드를 나타냅니다. 각 노드에는 스레드가 포함되어 있습니다. 스레드가 잠금 장치를 얻지 못한 후 먼저 동기화 큐를 큐에 들어갑니다. 조건부 대기열을 입력하려면 나사산이 잠금을 고정해야합니다. 다음으로 큐의 각 노드의 구조를 살펴 보겠습니다.
// 동기 큐의 노드는 정적 최종 클래스 노드 {정적 최종 노드 shared = new Node (); // 현재 스레드는 공유 모드에서 잠금을 고정합니다. static final node 독점 = null; // 현재 스레드는 독점 모드에서 잠금을 고정합니다. 정적 최종 int canceled = 1; // 현재 노드가 잠금 정적 최종 int 신호를 취소했습니다 = -1; // 후속 노드의 스레드는 정적 최종 int 조건을 실행해야합니다 = -2; // 현재 노드는 조건부 큐 정적 최종 int 전파 = -3에서 대기됩니다. // 후속 노드는 잠금 휘발성 int weatstatus를 직접 획득 할 수 있습니다. // 현재 노드 휘발성 노드의 대기 상태를 나타냅니다. // 동기화 큐에서 전방 노드를 표시합니다. // 동기화 큐 휘발성 스레드에서 후속 노드를 나타냅니다. // 현재 노드에서 보유한 스레드는 Node NextWaiter를 나타냅니다. // 조건부 대기열에서 후속 노드를 표시하십시오. // 공유 모드의 현재 노드 상태입니다. 최종 부울 isshared () {return nextwaiter == 공유; } // 현재 노드 최종 노드의 전방 노드를 반환합니다. 최종 노드 선임자 ()는 NullPointerException {Node p = prev; if (p == null) {throw new nullpointerexception (); } else {return p; }} // 생성자 1 node () {} // 생성자 2,이 생성자는 기본 노드 (스레드 스레드, 노드 모드)에서 사용됩니다 (// 홀딩 모드는 NextWaiter에 할당됩니다 .nextWaiter = mode; this.thread = 스레드; } // 생성자 3, Node (스레드 스레드, int weatstatus) 만 조건 큐 {this.waitstatus = waitstatus; this.thread = 스레드; }}노드는 동기화 큐의 노드와 조건부 큐의 노드를 나타냅니다. 그것은 추상적 인 queuedsynchronizer의 내부 클래스입니다. 노드는 홀딩 모드, 대기 상태, 사전 시급 및 동기 대기열의 후속 및 조건부 대기열의 후속 참조와 같은 많은 속성을 가지고 있습니다. 동기화 대기열 및 조건 대기열은 대기열 영역으로 간주 될 수 있으며 각 노드는 큐 영역에서 좌석으로 간주됩니다. 손님이 처음 오면 문을 두드려 자물쇠가 열리는지 확인합니다. 잠금 장치가 열리지 않으면 대기열 영역으로 가서 숫자 플레이트를 모으고 자물쇠를 잡고 싶은 방법을 선언하고 마침내 대기열 끝에서 대기열을 선언합니다.
4 독점 모드와 공유 모드를 이해하는 방법은 무엇입니까?
앞에서 언급했듯이 각 손님은 대기하기 전에 숫자 플레이트를 받고 자물쇠를 소유하고 싶다고 선언합니다. 잠금 장치를 소유하는 방법은 독점 모드 및 공유 모드로 나뉩니다. 그렇다면 독점 모드와 공유 모드를 어떻게 이해합니까? 나는 정말 좋은 비유를 찾을 수 없습니다. 공중 화장실을 생각할 수 있습니다. 독점 모드를 가진 사람들은 더 지배적입니다. 나는 들어 가지 않습니다. 내가 들어올 때, 나는 다른 사람들이 들어가는 것을 허용하지 않습니다. 나는 화장실 전체를 혼자 점령합니다. 공유 모드의 사람들은 그렇게 특별하지 않습니다. 화장실이 이미 사용할 수 있다는 것을 알게되면 그 자체로 들어 오면 계산되지 않습니다. 그들은 또한 사람들이 함께 사용하는지에 대한 열정적으로 사람들에게 열정적으로 물어봐야합니다. 뒤에있는 사람들이 함께 사용하지 않는다면 대기열을 줄 필요가 없습니다. 모두가 함께 갈 것입니다. 물론, 그 뒤에있는 사람들이 마음에 들면 대기열에 머무르고 계속 대기해야합니다.
5 노드의 대기 상태를 이해하는 방법은 무엇입니까?
또한 각 노드에는 대기 상태가 있으며,이 상태는 취소, 신호, 조건 및 전파의 네 가지 상태로 나뉩니다. 이 대기 상태는 좌석 옆에 매달려있는 표시로 간주되어 현재 좌석에있는 사람의 대기 상태를 식별합니다. 이 브랜드의 상태는 스스로 수정할 수있을뿐만 아니라 다른 브랜드도 수정할 수 있습니다. 예를 들어,이 스레드가 이미 대기열 중에 포기할 계획 인 경우, 좌석에 표시가 취소되도록 설정하여 다른 사람들이 보면 대기열에서 제거 할 수 있도록합니다. 또 다른 상황은 스레드가 좌석에서 잠들려고 할 때, 잠들게 될까 봐 두려워서, 전면 위치의 표시가 신호를 보내기 위해 신호를 보내기 전에 좌석으로 돌아 오기 때문에 큐를 떠나기 때문입니다. 표지판의 상태가 신호라는 것을 알면 다음 사람이 깨어날 것입니다. 전면 위치의 브랜드가 신호임을 확인함으로써 만 현재 실은 평화롭게 잠을 자게됩니다. 조건 상태는 나사산이 조건부 큐에서 대기열되었음을 나타냅니다. 전파 상태는 후속 스레드가 잠금을 직접 획득하도록 상기시킵니다. 이 상태는 공유 모드에서만 사용되며 공유 모드에 대해 별도로 이야기 할 때 나중에 논의됩니다.
6. 노드가 동기화 큐에 들어가면 어떤 작업이 수행됩니까?
// 노드 eNqueue 작동, 이전 노드 개인 노드 ENQ (최종 노드 노드) {for (;;) {// 동기화 큐 노드 T = Tail의 테일 노드에 대한 참조를 가져옵니다. // 테일 노드가 비어 있으면 (t == null) {// 동기화 큐를 초기화하면 동기화 큐가 초기화되지 않았 음을 의미합니다. if (compareAndSethead (node ()) {tail = head; }} else {// 1. 현재 꼬리 노드 노드를 가리 킵니다 .prev = t; // 2. 전류 노드를 꼬리 노드로 설정 if (compareAndSettail (t, node)) {// 3. 오래된 꼬리 노드의 후속 인을 새로운 테일 노드 T.next = 노드로 가리 킵니다. // for 루프의 유일한 종료는 t를 반환합니다. }}}}Enqueue 작동은 Dead Loop을 사용합니다. 노드가 동기화 큐의 꼬리에 성공적으로 추가 될 때만 반환됩니다. 결과는 동기화 큐의 원래 꼬리 노드입니다. 다음 그림은 전체 작동 프로세스를 보여줍니다.
독자는 테일 노드를 추가하는 순서에주의를 기울여야합니다.이 세 가지 단계로 나뉩니다. 테일 노드를 가리키고 CAS는 꼬리 노드를 변경하고 이전 테일 노드의 후속 장치를 현재 노드로 향하게됩니다. 동시 환경 에서이 세 단계는 완료되지 않을 수 있습니다. 따라서, 동기화 큐에서 취소 된 모든 노드를 지우는 작업에서 캔셀이 아닌 상태에서 노드를 찾기 위해 앞뒤로가 아니라 뒤쪽에서 앞쪽으로 이동합니다. 또한, 각 노드가 큐에 들어가면 대기 상태가 0입니다. 후속 노드의 스레드가 일시 중단 될 때만 이전 노드의 대기 상태가 신호로 변경됩니다.
참고 : 위의 모든 분석은 JDK1.7을 기반으로하며 다른 버전간에 차이가있을 것이므로 독자는주의를 기울여야합니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.