프로그래밍/JAVA

java 쓰레드풀(Thread pool) 을 활용한 멀티쓰레드 처리

내맘대로내뜻대로 2020. 12. 21. 11:52
728x90

java 뿐만 아니고 일반적인 프로그래밍에서 멀티쓰레드의 활용이 꼭 필요할때가 있습니다.

멀티쓰레드란 무엇인가? 라는 내용을 자세하기 기록하기엔 너무 양이 많고 간단한 예를 들어 설명 하겠습니다.

 

일반적으로 햄버거매장(맥도날드나 버거킹 등등..)에 가면 화면을 터치하여 주문하는 키오스크 주문기가 있습니다.

구매자는 키오스크에 자신이 원하는 메뉴를 선택하고 결재를 진행한 후 대기표를 받아 기다리게 되고

매장직원은 주문순서에 따라 조리를 시작합니다.

이때 주문이 각각 업무(job)가 되고, 직원은 쓰레드가 된다고 생각하면 이해가 간단해 집니다.

 

주문이 1건밖에 없을 경우 직원 1명이 이 업무를 처리하면 간단하게 해결됩니다.

 

주문이 10건이상 쌓이고 직원이 1명밖에 없다면 현재 진행중인 주문건 이외의 주문건은  계속 기다리며 차례차례(순차적) 진행하게 될것입니다.

 

이런 진행을 막기 위해 매장에서도 직원을 여러명 두게 되는데 직원이 1명일때보다 3명일때 처리속도가 3배 나오게 되며 직원수가 많을수록 일처리 속도는 빨라지게 될것입니다.

 

하지만 당연히 직원이 많을수록 매장에서 감당해야 하는 고용비용은 증가하게 되겠지요.

따라서 직원수와 업무처리 효율이 적절히 조절되어야 합니다.

 

자바에서 쓰레드를 처리하기 위한 방법은 여러가지가 있습니다.

 

멀티 쓰레드의 경우 업무 1건당 쓰레드 1개를 배정하여 사용하는 방식이 사용되기도 하는데 단순히 멀티 쓰레드 처리를 하게 될 경우 작업량에 따라 쓰레드가 계속 늘어나게 되어 오히려 작업효율이 떨어지거나 필요이상의 자원을 사용하게 되는 경우가 있습니다.

 

쓰레드풀(Thread pool)은 활용할 쓰레드의 최대값을 미리 지정하여 그 쓰레드 안에서 처리가 되는 방식입니다.

 

멀티 쓰레드 처리시 작업수와 같은수의 쓰레드가 동작하게 되면 햄버거 매장의 예에서 손님이 동시에 10명이 몰려들었을때 직원 10명이 일을 하려고 하지만 주방의 크기나 매장 크기가 충분히 넉넉하지 않다면 직원들의 동선이 충돌하고 업무처리가 오히려 늦어지는 상황이 발생할 수 있습니다.

프로그램 처리에서도 너무 많은 쓰레드를 사용하게 되면 과도하 부하로 오히려 속도가 늦어지고 심한경우 프로그램이 비정상종료되거나 멈추는 현상도 발생됩니다.

 

쓰레드풀을 활용 할 경우 동시에 처리 가능한 업무의 수는 쓰레드풀에 설정한 쓰레드 갯수만큼 이지만 먼저 작업이 끝난 유휴쓰레드가 다음 작업을 바로 진행하며 쌓여있는 작업이 계속 진행되므로 적당한 부하와 효율적인 업무처리가 진행됩니다.

 

멀티쓰레드를 활용하기 좋은 업무는 TPC/IP 통신(대기시간이 존재)이나 동영상의 인코딩(작업시간이 많이 소요될때) 작업이 여러건 진행되어야 할때 등 한건의 작업이 대기시간이나 소요시간이 길어 다음 작업들이 계속 앞의 업무가 끝날때까지 기다려야 할 경우 입니다.

 

 

쓰레드풀을 활용한 예제

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;



ExecutorService executorService = Executors.newFixedThreadPool(5);

if(rs!=null){
	while (rs.next())
	{
		Runnable runnable = new Runnable() {
			@Override
			public void run() {
				//실제 처리할 작업 
				System.out.println("이런 저러 처리...");
			}
		};

		executorService.execute(runnable);	 
	}
}
//쓰레드풀 종료
executorService.shutdown();

 

코드상 rs는 DB에서 값을 불러온 레코드셋 입니다.

DB에 값이 있을 경우 반환된 값의 갯수만큼 반복하게 되며 이때 각 작업은 쓰레드풀에서 지정한 5개의 쓰레드를 이용하여 처리하므로 처음 5건은 동시에 처리가 진행되고 그 다음 6번째건 부터 작업이 끝나기를 기다렸다가 작업이 끝난 쓰레드에서 처리가 됩니다.

의외로 처리가 간단하여 많이 활용 가능할것으로 생각됩니다.

 

우리가 직접 처리할 내용은 public void run() 으로 감싸고 그 밖을 런어블(Runnable)처리 해준 뒤 그 내용을 실행executorService.execute(runnable); 해주면 됩니다.

 

물론 모든 반복작업(멀티작업)이 끝난 후에는 쓰레드풀을 종료 해주어야 합니다.

executorService.shutdown();

 

약간 헷갈릴수 있는 문구가 5개의 쓰레드로 작업시 6번째 작업부터 대기한다는 부분일텐데요..

 

그럼 그냥 반복작업을 하는거보다 오히려 대기가 있어서 비효율인거 아닌가? 라는 의문을 가지는 분도 계실수 있는데..

단순 반복작업의 경우 쓰레드1개로 처리하는 상황이라 이미 2번째 작업부터 대기하고 있는 상황이므로 멀티 쓰레드 처리시 충분히 속도 향상이 있습니다.

 

 

* 개념도 같은건 시간 날때 그려서 추가 하겠습니다.

728x90