참고 공식문서 https://docs.oracle.com/javase/8/docs/api/java/util/AbstractQueue.html

티.꾸(TIL 꾸미기) 참 어렵다.. 이모지 고르는게 세상에서 제일 어려움
이번게시글은 동시성 2탄급 게시글이다..
공식 문서 요약:
1. FIFO(First-In-First-Out) 방식의 큐를 기반으로 한다.
2. add, remove, element 메서드는 fasle나 null 대신에 예외를 던지는 형태고, 내부적으로 offer, poll, peek 메서드에 위임한다.
3. 큐는 null 값을 저장하지 않는다. (넣으면 NullPointerException)
4. 이 클래스를 상속하는 클래스는 최소한 offer(E e), poll(), peek() 메서드를 구현해야 한다. (null 삽입 불가능XX)
※ 즉, 이 추상 클래스는 큐의 기본 골격만 제공하고, 실제 저장 방식이나 동시성 여부는 서브 클래스에서 정해야한다.

헐 사진 엄청 작네
ArrayBlockingQueue, ConcurrentLinkedQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, PriorityQueue, SynchronousQueue
가 있음
| 메서드 | 설명 |
|---|---|
put(E) | 큐/덱이 가득 차면 대기 (blocking) |
take() | 큐/덱이 비어있으면 대기 (blocking) |
offer(E) | 큐/덱이 가득 차면 false 반환 |
poll() | 큐/덱이 비어있으면 null 반환 |
peek() | 큐/덱의 첫 번째 요소 확인 (삭제X) |
size() | 현재 요소 수 반환 |
여튼 자주 사용되는 AbstractQueue 구현체에 대해서 ARABOZA
먼저, 이름부터 카테고리로 나눌 수 있음.

색깔에 비슷한거끼리 묶어봤다.
BlockingQueue 랑 Non-BlockingQueue로 나뉠 수 있고
Array/Linked/Priority 3개의 자료구조?? 로 나뉠 수 잇는거같아보인다.
실제 자료구조?는 이런식으로 확장되고 구현된다.


🟥 BlockingQueue (블로킹 큐)
ㅊㅊ https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html
put(): 큐가 가득 차면 대기.take(): 큐가 비어있으면 대기.공통적으로
ReentrantLock라는 동기화 방식을 사용한다. (아래 설명 추가)
🟦 Non-BlockingQueue (논블로킹 큐)
ㅊ https://www.baeldung.com/java-queue-linkedblocking-concurrentlinked
offer(): 큐가 가득 차면 false 반환.poll(): 큐가 비어있으면 null 반환.❓ 어떻게 락 없이 동시성 제어를 하지요??
=> CAS (Compare-And-Swap) 연산 사용
CPU 수준에서 지원하는 CAS 연산 (비원자적 비교-수정) 을 사용 << "값이 여전히 이전 상태라면 내가 원하는 값으로 바꿔줘!!"📌 CAS
// 의사코드 if (현재값 == 예상값) { 현재값 = 새값 return 성공 } else { return 실패 }
- 이 연산은 동시에 여러 스레드가 접근해도 경합을 일으키지 않고 하나만 성공함.
- 실패한 스레드는 다시 시도(재시도 루프)함 → 그래서
lock-free라고 해도 바보처럼 무한 루프 돌리는 건 아님.
ConcurrentLinkedQueue구조 같은 경우head와tail노드를AtomicReference로 감싸고 있음요소 삽입 (offer())시 : 마지막 노드에 새 노드를 연결하고, CAS로 tail 포인터를 새 노드로 바꿈
-> 다른 스레드가 동시에 삽입해도 CAS가 실패하면 재시도요소 제거 (poll())시 : head의 다음 노드를 읽고 CAS로 head를 이동시킴 (데이터는 next에 있음)

🟥 Array 기반
ArrayBlockingQueue🟦 Linked 기반
LinkedBlockingQueue, LinkedBlockingDeque출처: https://www.geeksforgeeks.org/priorityblockingqueue-class-in-java/
🟩 Priority 기반
PriorityBlockingQueue출처: https://www.geeksforgeeks.org/priorityblockingqueue-class-in-java/

정의: 내부에 저장 공간이 없는 큐로, 하나의 스레드가 put()을 호출하면 다른 스레드가 take()를 호출할 때까지 대기함.
특징:
용도:
요약은 지선생이

https://java-latte.blogspot.com/2013/10/arrayblockingqueue-in-java.html

ArrayBlockingQueue는 배열 기반의 고정 크기 FIFO(선입선출) 큐
이름 답게
Array("배열로 만들어진" + "크기가 고정된")
Blocking("스레드 안전한")
Queue("순서 지키는 큐")
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);

put("A") → A 들어감
put("B") → B 들어감
...
5개 다 차면 → 다음 put()은 블로킹 (멈춰서 기다림)
take() → 가장 앞의 A 나옴
비어 있으면 → take()는 대기함
생성자 옵션
ArrayBlockingQueue(int capacity) ArrayBlockingQueue(int capacity, boolean fair)
fair = true→ 공정성: 먼저 기다린 스레드가 먼저 락 획득 (FIFO 기반 락 큐)
fair = false→ 비공정: 빠른 스레드가 락을 먼저 가져갈 수 있음 → 성능은 더 좋음
1️⃣ 배열 기반이므로 공간이 연속적이고 성능이 예측 가능하다.
2️⃣ 크기가 고정된다.
3️⃣ 블로킹 기능이 내장되어 있다..
✅ Blocking(대기) 메커니즘이 필요한 경우
✅ 락 기반 동기화로 예측 가능한 동작을 원할 때 => 락 써야할 때!
❌ 비차단 고성능 처리가 필요할 때는 부적합
❌ 큐 크기를 유동적으로 늘려야 할 때는 부적합
https://www.prepbytes.com/blog/java/concurrentlinkedqueue-in-java-with-examples/
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
ConcurrentLinkedQueue는 락 없이 빠르고 안전하게 여러 스레드에서 동시에 접근 가능한 FIFO 큐로, 대용량/고빈도 작업에서 스레드 간 안전한 데이터 전달이 필요한 경우에 유용함.
ConcurrentLinkedQueue<E> queue = new ConcurrentLinkedQueue<>();

1️⃣ 무한 크기
2️⃣ Lock-Free 기반의 비차단(Non-blocking) 알고리즘
3️⃣ 내부적으로 싱글 연결 리스트(Singly Linked List) 구조를 사용
✅ 락 없이 성능을 높이고 싶을 때 => 락 사용x
✅ 메모리 사용이 유연해야 할 때
❌ 스케줄링 우선순위, 지연 처리 필요할 때는 부적합
여기까지해서 ArrayBlockingQueue 와 ConcurrentLinkedQueue의 간단비교!
ArrayBlockingQueuevsConcurrentLinkedQueue
즉, 스레드 세이프하는 알고리즘이 서로다르고 배열과 리스트의 차이정도가 있다.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/LinkedBlockingQueue.html
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/LinkedBlockingDeque.html
https://www.baeldung.com/java-blocking-queue
이름부터 Queue 와 Deque(덱) 라서 특징은 비슷할 것이라고 생각하고 같이 쓴다.
// LinkedBlockingQueue
LinkedBlockingQueue<E> queue = new LinkedBlockingQueue<>();
LinkedBlockingQueue<E> queue2 = new LinkedBlockingQueue<>(int capacity); // 기본은 무제한
// LinkedBlockingDeque
LinkedBlockingDeque<E> deque = new LinkedBlockingDeque<>();
LinkedBlockingDeque<E> deque2 = new LinkedBlockingDeque<>(int capacity);
capacity를 지정하지 않으면 Integer.MAX_VALUE가 최대 크기로 설정됨.
capacity를 지정하면 메모리 사용 제한 및 생산-소비 속도 제어 가능.
✅
LinkedBlockingDeque는덱이기 때문에 양쪽 삽입/삭제가 가능하다 (따로 사용하는 메서드가 더 있음)deque.offerFirst(e); deque.offerLast(e); deque.pollFirst(); deque.pollLast();이런식으로 앞/뒤 설정가능
이쯤되면 궁금증이 생길것이다.
정답은 ❌다.
AbstractQueue는 그 자체로는 Thread-safe하지 않으며, 그걸 상속한 각 구현체들이 Thread-safe 여부를 직접 구현 방식에 따라 결정 한다.

동기화 방식을 정리해봤는데 사진으로 알 수 있다 싶이
BlockingQueue는 ReentrantLock라는 동기화 방식을, 그 외에는 구현체마다 각각의 동기화 방식을 사용한다.
즉, BlockingQueue 인터페이스를 구현한 클래스들은 멀티스레드 환경에서 안전하게 작동하도록 설계되었음.
반면에 PriorityQueue는 동기화 코드 자체가 없다
PriorityQueue는 java.util.AbstractQueue의 하위 클래스암
PriorityBlockingQueue를 사용한다.
이건 BlockingQueue 인터페이스를 구현하고 있고,
내부적으로 ReentrantLock을 사용해 Thread-safe하게 동작함.
마찬가지로 우선순위 기반 정렬을 지원함.
PriorityBlockingQueue=BlockingQueue+PriorityQueue
ㅊㅊ : https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html
https://velog.io/@may_yun/JAVA-synchronized-VS-Reentrant-Lock-차이점
이야 오라클 공식문서 완전 친절해 ㅋㅋ
ReentrantLock의 동기화 방식은 Java에서 명시적인(lock-based) 방식으로 스레드 간 동기화를 제어하는 도구로써
스레드 간에 공유 자원에 대한 접근을 제어하기 위한 락(lock) 객체로 사용한다

이거 공식문서에 잇는 예제인데
객체 호출해서 lock으로 얻고, try-finally 부분에서 unlock()을 하는게, 이전시간에 사용했던 레투스와 거의 유사한 형태다.
참고로
lock.isHeldByCurrentThread(); 는
현재 스레드가 이 ReentrantLock을 보유하고 있는지 확인하는 메서드임
반환 값은 true/false
굳이굳이 자바에서 동기화를 관리해야해서 synchronized 같은 것을 메서드에 끼워넣을바엔 해당 도구를 사용해보자!!!
📌 synchronized는 공정성을 지원하지 않는다. 반면
ReentrantLock은 생성자의 인자를 통해서 공정/불공정 설정을 할 수 있다.
요즘에는 DB에 락 설정을 잘해놓으니깐 + redis 락이 좋으니깐 굳이 자바단에서 락 설정을 세세하게 할 필요 없는듯?
끝