JAVA WAS 서버를 구현하면서, 들었던 생각은 WAS 처럼 다중 접속 처리를 어떻게 해야하지? 에 대한 생각이었다.
기존 WAS 같읕 경우에는 따로 개발자가 처리해주지 않아도 DEFAULT로 설정된 값들로 멀티스레딩을 통해 동작하는데, 현재 순수 자바로 개발하고 있는 WAS 서버에서는 어떻게 멀티 스레딩을 지원해줄 수 있을 지 고민하였다.
java.util.concurrent 패키지에 포함되어 있는 인터페이스.스레드 풀 전략 을 통해 작업을 효과적으로 관리할 수 있게 해준다.execute(Runnable command) : 주어진 작업 실행, 작업은 Runnable 인터페이스를 구현한 객체로 표현shutdown() : 더 이상 새로운 작업을 받지 않고, 이미 제출된 작업 완료ExecutorService executor = new ThreadPoolExecutor(
...
);
Socket connection;
while ((connection = listenSocket.accept()) != null) {
executor.execute(new ConnectionHandler(connection));
}
executor.shutdown();
ExecutorService의 구현체 중 하나corePoolSize: 기본적으로 유지할 스레드 수. 이 수 이하의 스레드는 작업이 없어도 유지됨maximumPoolSize: 최대 스레드 수. 이 수를 초과하는 작업이 제출되면, 추가 작업은 큐에 대기keepAliveTime: 기본 스레드 수를 초과하는 스레드가 유휴 상태로 있을 수 있는 최대 시간. 이 시간이 지나면 스레드는 종료됨workQueue: 작업 큐입니다. 제출된 작업이 대기하는 공간. 일반적으로 LinkedBlockingQueue, SynchronousQueue 등이 사용됨ExecutorService executor = new ThreadPoolExecutor(
CORE_THREAD_SIZE, // 코어 스레드 개수
MAX_THREAD_SIZE, // 최대 스레드 개수
REST_TIME, // 놀고 있는 시간
TimeUnit.SECONDS, // 놀고 있는 시간 단위
new SynchronousQueue<Runnable>() // 작업 큐
);
ScheduledThreadPoolExecutor, ForkJoinPool, Executors 팩토리 메소드 등과 같은 방법들이 있지만, ThreadPoolExecutor을 사용한 이유는 아래와 같다.SynchronousQueue 를 사용했지만, LinkedBlockingQueue와 같은 것들도 사용해볼 수 있기 때문에 선택이 부분에 대해서는 리팩토링을 해보아야겠다고 생각한 게, 만약
다중 입력 대기 큐와 같은 것들을 구현하게 된다면,LinkedBlockingQueue를 통해 구현하는 게 조금 더 편하지 않았을까? 하는 고민이 되었다..!
다음 포스트에서 상세히 다뤄보겠다!
워크 스틸링 : 작업자 스레드가 일할 작업이 없으면 다른 스레드의 데크에서 작업을 가져온다. 이를 통해 스레드 간의 작업 부하를 균형잡히게 유지하고, 모든 스레드가 계속 작업을 수행할 수 있도록 한다. 일종의
로드 밸런서역할과 비슷한? 느낌!
결론적으로, java의 concurrent 패키지를 이용해서 멀티 스레딩에 대한 자원들을 효율적으로 관리하고 customize해서 사용할 수 있다는 것을 알게 되었다.
만약에, 나중에 기회가 된다면 이러한 수치들을 조절해서다중 대기 큐와 같은 것들을 구현해봐도 좋을 것 같다고 생각하였다.
활용될 수 있는 스레드 개수는 정해져 있을 때, 그보다 더 큰 요청들이 들어오게 된다면 그것들을 관리해주어야 하는 것도 필요하다고 생각했다. 추후에, 학습을 더 하고 난 후에 다중 대기 큐 같은 것들도 구현해보아야겠다!