스레드 풀

dawn·2021년 3월 14일
0

자바

목록 보기
4/9

1. 블로킹 방식의 작업 완료 통보

ExecutorService의 submit() 메소드는 매개값으로 준 Runnable 또는 Callable 작업을 스레드 풀의 작업 큐에 저장하고 즉시 Future객체를 리턴한다.

Future의 get()메소드를 호출하면 스레드가 작업을 완료할 떄까지 블로킹되었다가 작업을 완료하면 처리 결과를 리턴한다. 이것이 블로킹을 사용하는 작업 완료 통보 방식이다.

Future를 이용한 블로킹 방식의 작업 완료 통보에서 주의할 점은 작업을 처리하는 스레드가 작업을 완료하기 전까지는 get()메소드가 블로킹되므로 다른 코드를 실행할 수 없다. 그렇게 때문에 get()메소드를 호출하는 스레드는 새로운 스레드이거나 스레드풀의 또 다른 스레드가 되어야 한다.

  • 리턴값이 있는 작업 완료 통보
/**
 * 1부터 10까지의 합을 리턴하는 작업을 Callable객체로 생성하고, 스레드플의 스레드가 처리하도록 요청
 */
public class ResultByCallableExample {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService executorService = Executors.newFixedThreadPool( //스레드가 작업을 처리하지 않고 있더라도 스레드 개수가 줄지 않는다.
				Runtime.getRuntime().availableProcessors() //CPU코어의 수만큼 최대스레드를 사용하는 스래드 생성
				);
		
		Callable<Integer> callable = new Callable<Integer>() {
			@Override
			public  Integer call() throws Exception {
				int sum = 0;
				for(int i=1; i<=10; i++) {
					sum+=i;
				}
				return sum;
			}
		};
		
		//작업 큐에 callable객체를 저장하고 즉시 Future<T>를 리턴
		Future<Integer> future = executorService.submit(callable);
		
		try {
			//스레드풀의 스레드가 Callable의 객체의 call()메소드를 모두 실행하고 T 타입의 값을 리턴하면,
			//Future<T>의 get()메소드는 블로킹이 해제되고 T타입의 값을 리턴하게 된다.
			System.out.println(future.get());
		} catch (Exception e) {
			e.printStackTrace();
		} 
		executorService.shutdown();
	}
}

2. 작업 처리 결과를 외부 객체에 저장

스레드가 작업 처리를 완려하고 외부 Result객체에 작업 결과를 저장하면, 애플리케이션이 Result 객체를 사용할 수 있다.
대개 Result 객체는 공유 객체가 되어, 두개 이상의 스레드 작업을 취합할 목적으로 이용된다.

작업 객체는 Runnable 구현 클래스로 생성하는데, 주의할 점은 스레드에서 결과를 저장하게 위해 외부 Result 객체를 사용해야 하므로 생성자를 통해 Result 객체를 주입받도록 해야 한다.

다음 예제는 1부터 10까지의 합을 계산하는 두 개의 작업을 스레드풀에 처리요청하고, 각각의 스레드가 작업 처리를 완료한 후 산출된 값을 외부 Result 객체에 누적하도록 했다.

public class ResultByCallableExample2 {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService executorService = Executors.newFixedThreadPool(
				Runtime.getRuntime().availableProcessors()
				);
		
		
		System.out.println("[작업 처리 요청]");
		class Task implements Runnable {
			
			Result result;
			
			public Task(Result result) {
				this.result = result;
			}
			@Override
			public void run() {
				int sum = 0;
				for(int i=1; i<=10; i++) {
					sum += i;
				}
				result.addValue(sum);
			}
		};
		Result result = new Result();
		Runnable task1 = new Task(result);
		Runnable task2 = new Task(result);
		Future<Result> future2 =  executorService.submit(task2, result);
		Future<Result> future1 = executorService.submit(task1, result);
		try {
			future1.get();
			future2.get();
		} catch (InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(result.value);
	}
	
}
	class Result {
		int value;

		synchronized int addValue(int value) {
			this.value += value;
			return this.value;
		}
		
	}

* '이것이 자바다'라는 책을 읽고 정리한 내용입니다.

profile
안녕하세요

0개의 댓글