[JAVA WAS] 블로킹 큐

Zoonmy·2024년 6월 26일

JAVA WAS

목록 보기
3/5

앞선 게시물에서, 학습을 되돌아보다가 내가 왜 SynchronousQueue 를 사용했는 지에 대해 제대로 답변을 할 수 없었다.

쉬워 보이니까, 자료가 많으니까 써야지 보다는, 어떤 상황에서 어떤 것을 써야 좋을까? 에 대해 생각해보는 자세를 가지고 사용해야겠다!

LinkedBlockingQueue

특징

  • FIFO : 큐에 들어간 순서대로 처리

  • 크기 제한 : 큐의 용량 지정
    - 기본적으로는 무제한 크기를 가진다 (Integer.MAX_VALUE)

  • 생산자-소비자 패턴

    생산자가 데이터를 큐에 넣음
    ->
    소비자가 데이터를 큐에서 꺼냄

  • 버퍼링 : 데이터 버퍼링

    데이터 버퍼링이란?
    생산자가 데이터를 넣고 -> 소비자가 나중에 데이터를 꺼낼 수 있다.


SynchronousQueue

특징

  • 직접 전달 : 버퍼가 없다.
    - 요소가 큐에 삽입되려면, 반드시 다른 스레드가 그 요소를 즉시 꺼내야 함
  • 크기가 없다 : 큐에 저장 공간이 없음
    - 생산자 스레드가 put 을 호출 -> 소비자 스레드가 take를 호출할 때 까지 대기해야 함
  • 빠른 전송 : 즉시 데이터를 주고받으므로, 매우 빠른 전송 가능

비교

특성LinkedBlockingQueueSynchronousQueue
버퍼링가능 (크기 제한 가능)불가능 (버퍼 없음)
FIFO 순서지원N/A
생산자-소비자생산자와 소비자가 독립적으로 동작 가능생산자와 소비자가 즉시 만나야 함
대기 시간큐가 가득 차거나 비어 있을 때 대기생산자와 소비자가 즉시 만나지 않으면 대기
사용 사례데이터 버퍼링이 필요한 경우 (예: 로그 처리, 작업 큐)즉시 전달이 필요한 경우 (예: 작업 스레드 간 직접 통신)

그렇다면 다중 대기 큐 구현에는 무엇이 적합?

LinkedBlockingQueue를 사용하는 것이 좋다!

1) 버퍼링: LinkedBlockingQueue는 버퍼링을 지원하여 입력이 많을 때 대기 큐로 사용하기 적합

2) FIFO 순서 : 요청이 들어온 순서대로 처리 가능

구현해보기~!

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만 접속가능하도록 설정

동작 설명

  • 1000개의 요청이 들어오면, 처음 10개의 요청은 즉시 스레드 풀에 할당되어 처리
  • 나머지 990개의 요청은 LinkedBlockingQueue에 대기
  • 스레드가 요청을 처리 완료하면 대기 큐에서 새로운 요청을 가져와 처리
  • 큐의 용량이 가득 찬 경우, 새로운 요청은 큐에 여유 공간이 생길 때까지 대기

위의 예제를 통해 뭔가.. 대기 큐를 쉽게(?) 구현 할 수 있을 것 처럼 느껴졌다 .. [망상인듯함]

profile
열시미 해야쥐

0개의 댓글