ArrayBlockingQueue를 학습

면책 조항 :이 문서는 블로거 원본입니다은 허용 블로거없이 복제 할 수 없다. https://blog.csdn.net/ko0491/article/details/90903561

여기에 그림 삽입 설명

구조

ArrayBlockingQueue를 스토어 대기열 성분에 사용되는 내부 항목의 배열을 가지고,
첨자 변수가 대기열에 원소를 나타내고 putindex, takelndex 첨자가 큐잉된다 COU는 NT 큐 소자의 수를 계산. 주어진에서
는 이러한 변수 이러한 변수는 잠금 블록에 액세스 할 수 있기 때문에, 휘발성 수정을 사용하고, 추가하지 않은 것을 보여준다 의미
잠금 잠금 블록 변수 내부 메모리의 가시성을 확보 할 수있다. 또한 단독 잠금을 보장하는 잠금 장치가, 인큐 동작
하나의 스레드가 작업 대기열 디큐 수 없도록 자성. 또한,는 NotEmpty, notFull의
조건 변수는 대기열을 넣는 동기화를 위해 사용된다.

ArrayBlockingQueue 등 큐를 경계, 그래서 생성자는 반드시 수신 큐 크기 매개 변수 때문입니다.
코드 생성자는 다음과 같이.

 public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }
  public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }    

비 배타적 잠금에게 팀의 기본적 동기 운전에 의해 제공되는 공정 ReentrantLock와 사용.

작동 제공

큐가 이미 켜져있는 경우 대기열에 여유 공간이 존재하는 경우, 다음 사실 성공적인 복귀를 삽입, 큐의 꼬리에 요소를 삽입
완전하고 현재 요소가 false를 돌려 버리고. 전자 요소는 다음 NullPointerException이 예외 null의 경우. 또한,
이 방법은 차단되지 않는다.

 public boolean offer(E e) {
 //1 检查元素是否为空,为空就抛出空指针
        checkNotNull(e);
        //2 获取独占锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        //3 如果队列满则返回 false
            if (count == items.length)
                return false;
            else {
            //4 否则插入元素
                enqueue(e);
                return true;
            }
        } finally {
        //5 
            lock.unlock();
        }
    }

코드 - 2 배타적 잠금, 잠금을 획득하기 위해 현재 스레드, 다른 대기열에서 스레드 작업이 차단됩니다 획득
큐를 차단 잠금 잠금 AQS 후 끊기에 플러그를.
큐 코드 가득 경우 -3 그렇지 않으면, 통화 대기열 방법 후 true를 반환하고, 직접 false를 반환 결정
은 다음과 같이 대기열 코드입니다.

  private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        // 6 元素入队
        final Object[] items = this.items;
        items[putIndex] = x;
        // 7 计算下一个元素应该存放的下标位置
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        // 8 
        notEmpty.signal();
    }

우선, 현재의 배열 요소 항목으로하고 다음 인덱스 요소의 위치를 저장한다 계산
및 요소의 카운터 번호, 통화 조작 취할 차단되기 때문에 마지막 활성 큐는 NotEmpty 조건 증가
스레드. 어떠한 메모리도 없다 여기서 로크의 조작 횟수 전에 공유 변수 때문에, 표시되지 않도록하고 걸쳐 첨가
공유 변수 락 취득하지 캐시 또는 CPU 레지스터에서, 메인 메모리로부터 취득한다.

코드 5 릴리스 잠금 한 다음, 다시 메인 메모리 새로 고침> 등의 카운트 값과 공유 변수 값을 (수정합니다
다른 스레드 잠금 다시이 공유 변수를 읽을 때, 당신은 최신 값을 볼 수 있습니다.

작업을 넣어 - 인터럽트

큐는 큐가 이미 가득 직접하는 경우는 true 반환을 삽입 유휴 경우, 큐의 끝에 요소를 삽입 한 후
블록 큐가 성공적으로 삽입 후 유휴 진정한 돌아올 때까지 현재의 thread 아니라, 다른 스레드에 의해 차단시 설정하면
인터럽트 플래그를, InteηuptedException는 스레드가 예외 수익을 발생합니다 차단했다. 또한, 소자 E가 널인 경우
다음 NullPointerException이 예외.

   public void put(E e) throws InterruptedException {
   //1. 验证是否为空
        checkNotNull(e);
        //2.获取独占锁 可中断
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
        //3 如查队列满,则把当前线程放入notFull管理的条件队列
            while (count == items.length)
                notFull.await();
                //4 入队
            enqueue(e);
        } finally {
        //5 解锁
            lock.unlock();
        }
    }

코드에서 (2) 다른 스레드에 의해 중단되어 현재의 thread의 잠금을 획득하는 과정에서, 현재의 thread가 발생합니다
의 InterruptedException 예외 출구.
NotFull 현재 대기열이 이미 가득 차 있는지 확인하는 코드 (3) 다음에 위치, 큐 상태 보류 차단, 현재의 thread를 넣고,
여기에 관심을 문 경우 WHI 르 루프 대신에 사용된다.
큐 삽입 현재 요소 미만인 경우 코드는 (4) 결정

설문 조사 작업 - 인터럽트하지

큐의 헤드로부터 취득하고, 큐가 비어 널 반환되면 요소를 제거하는 과정은 차단되지

    public E poll() {
    //1. 获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        //2 当前队列为空则返回 null , 否则调用 dequeue获取
            return (count == 0) ? null : dequeue();
        } finally {
            lock.unlock();
        }
    }
    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        // 4获取元素值
        E x = (E) items[takeIndex];
        //5 数组中的值为 null
        items[takeIndex] = null;
        //6 队头指针再次计算,队列元素个数减 1
        if (++takeIndex == items.length)
            takeIndex = 0;
            //队列元素个数减 1
        count--;
        if (itrs != null)
            itrs.elementDequeued();
            //发送信号激活notFull条件队列 里面的一个线程
        notFull.signal();
        return x;
    }

먼저 현재 헤드 구성 요소를 취득하고, 상기 헤드 소자를 리셋 한 후, 로컬 변수에 저장
널 및 첨자 HOL 재설정 카운터 소자를 감소, 최종 전송 상태 신호 활성화 큐 notFull
메소드 호출 넣어 내부 차단 된 스레드

조치를 취할 - 인터럽트


    public E take() throws InterruptedException {
    //1.获取锁
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
        //2 队列为空,则等待,直到队列中有元素
            while (count == 0)
                notEmpty.await();
                //3 出队列 获取队头元素
            return dequeue();
        } finally {
        //4 解锁
            lock.unlock();
        }
    }

큐가되면
다시 넣어 비어는 NotEmpty는 현재 스레드 상태 큐를 걸어 놓고, 다른 스레드가 notEmpty.signal () 메서드를 호출
하고 반환합니다. 그 참고, 여기 잘 기다릴 대신 if 문을 사용하여 감지하는 while 루프를 사용합니다.

들여다 운영

큐 요소의 머리를 가져하지만 큐는 null, 프로세스가되지 돌려 비어있는 경우, 큐 내부에서 제거되지 않습니다
차단.


   public E peek() {
   //1. 获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        //2. 获取头元素
            return itemAt(takeIndex); // null when queue is empty
        } finally {
        //3 .解锁
            lock.unlock();
        }
    }
  • itemAt 방법

final E itemAt(int i) {
        return (E) items[i];
    }

첫째, 독점 잠금을 획득 한 다음 항목의 배열에서 머리에서 현재 팀의 기본 가치를 얻을 및
잠금의 해제를 얻기 위해 반환하기 전에, 반환

크기 작업

  public int size() {
  //1 获取独占锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        //2. 返回元素个数
            return count;
        } finally {
        //3 解锁
            lock.unlock();
        }
    }

취득 후 잠금 직접 계산 반환 및 이전 릴리스에 잠금을 반환합니다. 당신은, 요청할 수도
계수의 값을 수정하지 않습니다 차례, 간단하게, 왜 자물쇠거야? 카운트가 선언 된 경우 사실,
휘발성으로 휘발성 변수는 메모리의 시인성을 확보하고 있기 때문에 여기에 우리는 갇혀 할 필요가 없습니다
개수가 휘발성 선언되지 않은 ArrayBlockingQueue를 카운트 작업 원에 있기 때문에,
로크 복용 후에 수행되지만 잠금 의미 중 하나를 취득하고, 변수 보장 메인 메모리로부터 얻어지는 락 얻은 후 액세스되는
변수를 메모리 카드 가시성.
여기에 그림 삽입 설명

하나의 광고 동안 달성 글로벌 배타적 로크 ArrayBlockingQueue를 이용하여
구동 인큐 또는 디큐 동작은 상기 잠금 단위가 비교적 큰 동기 부가하는 다소 유사한 방법에
수단. 그들. 그는 연구 및 조사 작업 간단한 잠금 엔큐, 디큐 운영하여, 작업을 넣어
큐가 빈 다음, 각각의 경우 큐가 전체 대기 인 경우, 잠깐, 달성 변수 조건을
팀과를 팀 작업은 동기화 대기 스레드를 활성화하는 신호를 전송한다. 또한, LinkedBlockingQueue를 비교
정확한 동작에 ArrayBlockingQueue 크기의 결과, 이전에 플러스 글로벌 잠금과 같이 계산된다.

추천

출처blog.csdn.net/ko0491/article/details/90903561