JavaDocs에서 :
- ConcurrentLinkedQueue를이 많은 스레드가 공통의 컬렉션에 대한 액세스를 공유 적절한 선택이 될 것입니다. 이 큐는 널 요소를 허용하지 않습니다.
- ArrayBlockingQueue 는 고정 된 크기의 배열이 생산자가 삽입하고 소비자가 추출한 요소를 보유하는 클래식 “바운드 버퍼”입니다. 이 클래스는 대기중인 생산자 및 소비자 스레드 주문에 대한 선택적 공정성 정책을 지원합니다.
- LinkedBlockingQueue는 일반적으로 어레이 기반 대기열보다 처리량이 많지만 대부분의 동시 응용 프로그램에서 예측 가능한 성능은 떨어집니다.
두 가지 시나리오가 있습니다. 하나는 하나의 소비자와 많은 생산자 (이를 사용하는 스레드)를 지원하기 위해 대기열이 필요하고 다른 하나는 다른 방법입니다.
사용할 구현을 이해하지 못합니다. 차이점이 무엇인지 누군가가 설명 할 수 있습니까?
또한 ‘선택적 공정성 정책’ ArrayBlockingQueue
이란 무엇입니까?
답변
기본적으로 이들의 차이점은 성능 특성과 차단 동작입니다.
가장 쉬운 방법 ArrayBlockingQueue
은 고정 된 크기의 대기열입니다. 따라서 크기를 10으로 설정하고 11 번째 요소를 삽입하려고하면 다른 스레드가 요소를 제거 할 때까지 insert 문이 차단됩니다. 공정성 문제는 여러 스레드가 동시에 삽입 및 제거하려고 시도하는 경우 (즉, 큐가 차단 된 기간 동안) 발생합니다. 공정성 알고리즘은 요청한 첫 번째 스레드가 첫 번째 스레드가되도록합니다. 그렇지 않으면, 주어진 스레드가 다른 스레드보다 더 오래 대기하여 예기치 않은 동작을 유발할 수 있습니다 (때때로 시작된 다른 스레드가 먼저 처리되기 때문에 한 스레드가 몇 초 정도 걸리기도합니다). 단점은 공정성을 관리하는 데 오버 헤드가 발생하여 처리량이 느려진다는 것입니다.
가장 중요한 차이점 LinkedBlockingQueue
및 ConcurrentLinkedQueue
당신이에서 요소를 요청하는 경우이다 LinkedBlockingQueue
큐가 비어있는 무언가가있을 때까지, 당신의 스레드가 대기합니다. ConcurrentLinkedQueue
빈 대기열의 동작으로 A 가 즉시 반환됩니다.
차단이 필요한지 여부에 따라 다릅니다. 많은 생산자와 하나의 소비자가있는 경우에는 그 소리처럼 들립니다. 반면에 소비자가 많고 생산자가 한 명인 경우 차단 동작이 필요하지 않을 수 있으며 소비자가 대기열이 비어 있는지 확인하고 대기열이 비어 있는지 계속 확인하게되어 기쁠 수도 있습니다.
답변
ConcurrentLinkedQueue 는 잠금이 수행되지 않음을 의미합니다 (즉, 동기화 (this) 또는 Lock.lock 호출 이 없음 ). 그것은 사용 비교 및 스왑 – CAS 헤드 / 테일 노드가 여전히 시작했을 때와 동일합니다 있는지 확인하기 위해 수정하는 동안 작업을. 그렇다면 작업이 성공합니다. 헤드 / 테일 노드가 다른 경우 회전하여 다시 시도합니다.
LinkedBlockingQueue 는 수정하기 전에 잠금을 수행합니다. 따라서 오퍼 통화는 잠길 때까지 차단됩니다. 추가를 포기하기 전에 X 시간 동안 만 기꺼이 기다린다고 말하는데 TimeUnit을 사용하는 오퍼 오버로드를 사용할 수 있습니다 (일반적으로 메시지가 X 밀리 초 후에 오래된 메시지 유형 큐에 적합 함).
공정성은 잠금 구현이 스레드 순서를 유지함을 의미합니다. 스레드 A가 들어간 다음 스레드 B가 들어 오면 스레드 A가 먼저 잠금을 얻습니다. 공정성이 없으면 실제로 어떤 일이 발생하는지 정의되지 않습니다. 예정된 다음 스레드 일 가능성이 높습니다.
어느 것을 사용할지는 달려 있습니다. 생산자가 대기열에 올리는 데 시간이 걸리기 때문에 ConcurrentLinkedQueue 를 사용하는 경향이 있습니다 . 나는 같은 순간에 생산하는 생산자가 많지 않습니다. 그러나 여론 조사는 좋은 수면 상태로 들어 가지 않기 때문에 소비자 측이 더 복잡합니다. 직접 처리해야합니다.
답변
질문 제목에 블로킹 대기열이 언급되어 있습니다. 그러나 차단 대기열 ConcurrentLinkedQueue
이 아닙니다 .
BlockingQueue
의는 ArrayBlockingQueue
, DelayQueue
, LinkedBlockingDeque
, LinkedBlockingQueue
, PriorityBlockingQueue
,와 SynchronousQueue
.
이들 중 일부는 분명 목적에 적합하지 않은 ( DelayQueue
, PriorityBlockingQueue
, 및 SynchronousQueue
). 후자는 이중 엔드 큐 (Deque 인터페이스를 구현 함)라는 점을 제외 LinkedBlockingQueue
하고 LinkedBlockingDeque
는 동일합니다.
ArrayBlockingQueue
요소 수를 제한하려는 경우에만 유용 하기 때문에 에 충실합니다 LinkedBlockingQueue
.
답변
ArrayBlockingQueue는 메모리 풋 프린트가 낮기 때문에 새로운 삽입마다 LinkedBlockingQueue $ Node 객체를 작성해야하는 LinkedBlockingQueue와 달리 요소 노드를 재사용 할 수 있습니다.
답변
SynchronousQueue
LinkedBlockingQueue
단일 요소를 허용하는 반면, 더 많은 핸드 오프 입니다. 차이가 있다고되는 put()
(A)에 호출 SynchronousQueue
대응있을 때까지 리턴되지 take()
호출하지만과 LinkedBlockingQueue
크기 1의 put()
(비어있는 큐) 호출은 즉시 복귀된다. 그것은 BlockingQueue
실제로 큐를 원하지 않을 때 (보류중인 데이터를 유지하고 싶지 않은) 구현입니다.
LinkedBlockingQueue
(LinkedList
구현하지만 정확하게 JDK 구현LinkedList
은 정적 내부 클래스 노드를 사용하여 요소 간의 링크를 유지합니다)
LinkedBlockingQueue의 생성자
public LinkedBlockingQueue(int capacity)
{
if (capacity < = 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node< E >(null); // Maintains a underlying linkedlist. ( Use when size is not known )
}
링크를 유지하는 데 사용되는 노드 클래스
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
삼 . ArrayBlockingQueue (배열 구현)
ArrayBlockingQueue의 생성자
public ArrayBlockingQueue(int capacity, boolean fair)
{
if (capacity < = 0)
throw new IllegalArgumentException();
this.items = new Object[capacity]; // Maintains a underlying array
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
IMHO 가장 큰 생성자 ArrayBlockingQueue
와의 차이점 LinkedBlockingQueue
은 생성자 하나가 기본 데이터 구조 Array 및 기타 linkedList를 가지고 있다는 것 입니다.
ArrayBlockingQueue
사용 단일 이중 잠금 상태 알고리즘 및 LinkedBlockingQueue
은 “두 로크 큐”알고리즘의 변형이며 2 잠금 2 조건 (takeLock, putLock)이
답변
ConcurrentLinkedQueue에 잠금이없고 LinkedBlockingQueue가 없습니다. LinkedBlockingQueue.put () 또는 LinkedBlockingQueue.take ()를 호출 할 때마다 먼저 잠금을 획득해야합니다. 즉, LinkedBlockingQueue의 동시성이 좋지 않습니다. 성능이 마음에 들면 ConcurrentLinkedQueue + LockSupport를 시도하십시오.