앞선 게시물에서, 학습을 되돌아보다가 내가 왜 SynchronousQueue 를 사용했는 지에 대해 제대로 답변을 할 수 없었다.
쉬워 보이니까, 자료가 많으니까 써야지 보다는, 어떤 상황에서 어떤 것을 써야 좋을까? 에 대해 생각해보는 자세를 가지고 사용해야겠다!
FIFO : 큐에 들어간 순서대로 처리
크기 제한 : 큐의 용량 지정
- 기본적으로는 무제한 크기를 가진다 (Integer.MAX_VALUE)
생산자-소비자 패턴
생산자가 데이터를 큐에 넣음
->
소비자가 데이터를 큐에서 꺼냄
버퍼링 : 데이터 버퍼링
데이터 버퍼링이란?
생산자가 데이터를 넣고 -> 소비자가나중에데이터를 꺼낼 수 있다.
put 을 호출 -> 소비자 스레드가 take를 호출할 때 까지 대기해야 함| 특성 | LinkedBlockingQueue | SynchronousQueue |
|---|---|---|
| 버퍼링 | 가능 (크기 제한 가능) | 불가능 (버퍼 없음) |
| FIFO 순서 | 지원 | N/A |
| 생산자-소비자 | 생산자와 소비자가 독립적으로 동작 가능 | 생산자와 소비자가 즉시 만나야 함 |
| 대기 시간 | 큐가 가득 차거나 비어 있을 때 대기 | 생산자와 소비자가 즉시 만나지 않으면 대기 |
| 사용 사례 | 데이터 버퍼링이 필요한 경우 (예: 로그 처리, 작업 큐) | 즉시 전달이 필요한 경우 (예: 작업 스레드 간 직접 통신) |
import java.util.concurrent.*;
public class WebServer {
private static final int N_THREADS = 10;
private static final int QUEUE_CAPACITY = 100;
public static void main(String[] args) {
LinkedBlockingQueue<Runnable> requestQueue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
N_THREADS,
N_THREADS,
0L,
TimeUnit.MILLISECONDS,
requestQueue
);
// WAS 시작
for (int i = 0; i < 1000; i++) {
final int requestId = i;
executor.execute(() -> handleRequest(requestId));
}
executor.shutdown();
}
private static void handleRequest(int requestId) {
System.out.println("Handling request: " + requestId);
// 요청 처리 로직
try {
Thread.sleep(100); // 요청 처리 시간 시뮬레이션
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Finished request: " + requestId);
}
}
QUEUE_CAPACITY를 통해 서버 과부하 방지 -> 접근자 수 제한corePoolSize, maximumPoolSize 를 동일하게 설정하여 항상 10명의 CLIENT만 접속가능하도록 설정위의 예제를 통해 뭔가.. 대기 큐를 쉽게(?) 구현 할 수 있을 것 처럼 느껴졌다 .. [망상인듯함]