답변:
생산자 / 소비자 스레드의 ConcurrentLinkedQueue
경우 이것이 합리적인 옵션이라고 확신하지 못합니다 BlockingQueue
. 생산자 / 소비자 대기열 IMO의 기본 인터페이스 인을 구현하지 않습니다 . 을 (를) 호출 poll()
하고 아무것도 찾지 못한 경우 잠시 기다린 다음 다시 폴링해야합니다. 새 항목이 들어 오면 지연되고 비어 있으면 비효율적으로 발생합니다 (불필요하게 잠에서 깨어남). .
BlockingQueue에 대한 문서에서 :
BlockingQueue
구현은 주로 생산자-소비자 대기열에 사용되도록 설계되었습니다.
나는 그것을하지 않습니다 알고 엄격하게 에만 블로킹 큐는 생산자 - 소비자 큐에 사용하지만, 심지어해야한다는 말을 ...
ConcurrentLinkedQueue
는 스레드가 여러 큐를 확인하는 경우에도 유용합니다. 예를 들어, 다중 테넌트 서버에서. 격리 이유 때문에 단일 차단 대기열과 테넌트 판별자를 대신 사용하지 않는다고 가정합니다.
take()
하고 put()
.NET보다 추가 리소스 (동기화 기간)를 소비하는 경우에만 참으로 유지됩니다 ConcurrentLinkedQueue
. 생산자-소비자 시나리오에
이 질문은 더 나은 대답을 할 가치가 있습니다.
Java ConcurrentLinkedQueue
는 비 블로킹 잠금없는 대기열에 대해 Maged M. Michael과 Michael L. Scott 의 유명한 알고리즘을 기반으로합니다 .
여기서 경합 리소스 (우리 대기열)의 용어로 "비 차단"이란 스레드 중단과 같이 플랫폼의 스케줄러가 수행하는 작업에 관계없이 해당 스레드가 단순히 너무 느리다면 다른 스레드가 동일한 리소스에 대해 경합하는 것을 의미합니다. 계속 진행할 수 있습니다. 예를 들어 잠금이 관련되면 잠금을 보유한 스레드가 중단 될 수 있으며 해당 잠금을 기다리는 모든 스레드가 차단됩니다. synchronized
Java 의 고유 잠금 ( 키워드)은 바이어스 잠금 과 같이 성능에 심각한 불이익을 줄 수 있습니다.관련되고 경합이 있거나 VM이 스핀 유예 기간 후 잠금을 "팽창"하고 경합 스레드를 차단하기로 결정한 후 ... 이것이 많은 상황에서 (낮음 / 중간 경합 시나리오) 비교 및 수행 -원자 참조에 대한 집합은 훨씬 더 효율적일 수 있으며 이것이 바로 많은 비 차단 데이터 구조가 수행하는 작업입니다.
자바 ConcurrentLinkedQueue
는 비차 단일뿐만 아니라 생산자가 소비자와 경쟁하지 않는 멋진 속성을 가지고 있습니다. 단일 생산자 / 단일 소비자 시나리오 (SPSC)에서 이것은 실제로 말할 경합이 없음을 의미합니다. 다중 생산자 / 단일 소비자 시나리오에서 소비자는 생산자와 경쟁하지 않습니다. 이 대기열은 여러 생산자가을 시도 할 때 경합이 offer()
있지만 이는 정의상 동시성입니다. 기본적으로 범용이며 효율적인 비 차단 대기열입니다.
그것이 아닌 것에 관해서 BlockingQueue
는 스레드가 대기열에서 대기하도록 차단하는 것은 동시 시스템을 설계하는 끔찍한 방법입니다. 하지마. ConcurrentLinkedQueue
소비자 / 생산자 시나리오에서 를 사용하는 방법을 알아낼 수없는 경우 좋은 행위자 프레임 워크와 같은 더 높은 수준의 추상화로 전환하십시오.
LinkedBlockingQueue
큐가 비어 있거나 가득 차고 각 소비자 / 생산자 스레드가 휴면 상태가 될 때 소비자 또는 생산자를 차단합니다. 그러나이 차단 기능에는 비용이 수반됩니다. 모든 풋 또는 테이크 작업은 생산자 또는 소비자 (많은 경우)간에 경합되는 잠금이므로 생산자 / 소비자가 많은 시나리오에서는 작업이 느려질 수 있습니다.
ConcurrentLinkedQueue
풋 / 테이크 작업에서 잠금을 사용하지 않고 CAS 는 잠재적으로 많은 생산자 및 소비자 스레드와의 경합을 줄입니다. 그러나 "wait free"데이터 구조 ConcurrentLinkedQueue
는 비어있을 때 차단되지 않습니다. 즉 , 소비자 스레드가 CPU를 소모하는 경우와 같이 소비자가 "바쁨 대기" take()
로 반환 null
값 을 처리해야합니다 .
따라서 어느 것이 "더 좋은지"는 소비자 스레드의 수, 소비 / 생산 속도 등에 따라 달라집니다. 각 시나리오에 대한 벤치 마크가 필요합니다.
ConcurrentLinkedQueue
분명히 더 나은 한 가지 특별한 사용 사례 는 생산자가 처음으로 무언가를 생산하고 작업을 대기열에 배치하여 작업을 완료 하고 소비자가 소비를 시작한 후에야 대기열이 비어있을 때 완료된다는 것을 알고있는 경우입니다. (여기에 생산자-소비자 간에는 동시성이 없지만 생산자-생산자 및 소비자-소비자간에 만 동시성이 있습니다.)
unbounded blockingqueue
사용된다면 CAS 기반 동시 사용 보다 더 좋을 것입니다ConcurrentLinkedQueue
(잘 확장되지 않는) 또 다른 솔루션은 랑데뷰 채널입니다. java.util.concurrent SynchronousQueue