Thread Pool은 다수의 스레드 자원 할당을 좀 더 효율적으로 하는 작업이다.


Thread pool을 생성 할 때 스레드 수를 지정하고


Runnable 작업이나 Callable 작업을 받고 실행된다.


단순하게 thread.start를 한다면 os의 작업 스케줄링으로 작업이 진행되는데


pool은 작업 할 Thread 수를 미리 설정해서 스케줄링이 진행된다.


하지만 Thread 수를 잘 못 예측하여 높게 잡는다면 오히려 메모리 공간이 낭비된다.




Runnable 작업은 Return값이 없고


Callable 작업은 Return값이 있는게 특징이다.


생성된 작업은 submit(), execute()로 실행되고


execute는 반환값이 없고 예외가 발생하면 스레드가 제거되는 반면


submit은 Future타입을 반환하고 예외상황에도 스레드를 재사용한다.




Thread Pool은 main Thread가 종료되도 남아있기 때문에 상태를 확인하고 따로 종료를 해주어야 한다.


shutdown()은 현재 작업을 마무리 후 종료시키고 shutdownNow()는 interrupt를 일으켜 강제 종료시킨다.



package chap10.exam13.pool;

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

public class ThreadPool {

	public static void main(String[] args) {
		// ThreadPool 생성 방법
		// 1개 이상의 스레드가 추가 되었을 때 60초 이상 놀고 있으면 제거
		// 작은 캐쉬 메모리 방에서 오래 붙들고 있으면 낭비가 심하기 때문에 제거
		ExecutorService pool = Executors.newCachedThreadPool();
		
		// 실행환경, 현재 이용할 수 있는 스레드, 프로세서 불러오는 방법
		// 현재 CPU에서 코어 갯수를 추출하는 방법.
		int n = Runtime.getRuntime().availableProcessors(); 
		System.out.println("가용 할 수 있는 스레드 갯수 : " + n);
		// 사용할 스레드, 프로세서 갯수를 지정하는법
		// 기본적으로 n개의 스레드를 유지
		pool = Executors.newFixedThreadPool(n);
	}

}







package chap10.exam14.exec;

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

public class ExecuteMain {

	public static void main(String[] args) throws InterruptedException {
		// Runnable로 작업 요청
		// execute() : 용서 X, 반환 X // 혼자 실행
		// submit() : 용서 O, 반환 O // 전송에는 답변이 있어야 함
		
		// 스레드 순서가 중요
		// 1. 스레드 풀 생성
		int n = Runtime.getRuntime().availableProcessors();
		ExecutorService pool = Executors.newFixedThreadPool(n);
		// 2. 할 일 지정
		Runnable runnable = new Runnable() {
			
			@Override
			public void run() {
				System.out.println("Runnable 처리");
			}
		};
		// 3. 실행
		pool.execute(runnable); // 반환 값 X
		
		
		// 4. 스레드 풀 종료(close)
		// 처리중인 작업이 마무리 되면 닫는다.
		pool.shutdown();
		// 처리중인 작업에 관계없이 강제로 닫는다.
//		pool.shutdownNow();
		// shutdown()이 타임아웃안에 실행 되는지 반환
		// 제한 시간안에 작업 완료시 true를 반환
		// 만약 제한시간을 지날경우 강제로 닫음
//		boolean t = pool.awaitTermination(10L, TimeUnit.SECONDS);
		
		
	}

}


package chap10.exam14.exec;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Submit {

	public static void main(String[] args) throws Exception {
		// 1. 스레드 풀 생성
		ExecutorService pool = Executors.newCachedThreadPool();
		
		// 2. 할 일 만들기
		Callable<String> callable = new Callable<String>() {

			@Override
			public String call() throws Exception {
				System.out.println("Callable 처리");
				return "작업완료";
			}
		};
		// 3. 실행
		Future<String> submit = pool.submit(callable);
		System.out.println(submit.get());
		
		// 4. 스레드 풀 닫기
		pool.shutdown();
		
	}

}


package chap10.exam14.exec;

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

public class TestPool {

	public static void main(String[] args) throws Exception {
		// Thread Pool 10번 출력하기

		// Runnable 사용, 순차실행
		// 1. 스레드 풀 생성
		int n = Runtime.getRuntime().availableProcessors();
		ExecutorService pool = Executors.newFixedThreadPool(n);
		// 2. 할 일 지정
		Runnable runnable = new Runnable() {

			@Override
			public void run() {
				for(int i = 0; i < 10; i++) {
					System.out.println("Thread Pool " + (i + 1) + "번");
				}
				System.out.println("----------------------------");
			}
		};
		// 3. 실행
		pool.execute(runnable); // 반환 값 X

		// 4. 스레드 풀 종료(close)
		pool.shutdown();





		// Callable 사용, 자기 마음대로 실행
		// 1. 스레드 풀 생성
		ExecutorService pool2 = Executors.newCachedThreadPool();

		// 2. 할 일 만들기
		Callable<String> callable = new Callable<String>() {

			@Override
			public String call() throws Exception {

				System.out.println("Thread Pool1");

				return "작업완료";
			}
		};

		// 3. 실행
		Future<String> submit = null;
		for(int i =0; i < 10; i++) {
			System.out.print(i + " : ");
			submit = pool2.submit(callable);
		}
		System.out.println(submit.get());

		// 4. 스레드 풀 닫기
		pool2.shutdown();

	}

}



Thread Pool은 runnable이나 callable에 관계없이 작업이 완료되면 Future객체를 반환한다.


그 Future 객체를 가져오는 get 메소드는 join과 같은 역할을 수행하고


이러한 작업을 Pool Blocking이라고 한다.



package chap10.exam15.block;

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

public class NoResultMain {

	public static void main(String[] args) throws Exception {

		int n = Runtime.getRuntime().availableProcessors();
		ExecutorService pool = Executors.newFixedThreadPool(n);

		Runnable runnable = new Runnable() {

			@Override
			public void run() {
				for(int i = 0; i < 10; i++) {
					System.out.println("Thread Pool " + (i + 1) + "번");
				}
				System.out.println("----------------------------");
			}
		};
		
		Future future = pool.submit(runnable); // 반환할게 따로 없으므로 제너릭 지워줌
		// 반환값이 없는데 get() 사용 이유
		future.get(); // get() == join() / 이 아래 내용이 반환 후 실행
		System.out.println("작업 완료");
		pool.shutdown();
	}

}


package chap10.exam15.block;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ResultMain {

	public static void main(String[] args) throws Exception {
		// 1. 풀 생성
		int n = Runtime.getRuntime().availableProcessors();
		ExecutorService pool = Executors.newFixedThreadPool(n);
		// 2. 해야 할 일
		Callable<Integer> task = new Callable<Integer>() {

			@Override
			public Integer call() throws Exception {
				int sum = 0;
				for(int i = 1; i <= 100; i++) {
					sum += i;
				}
				return sum;
			}
		};
		// 3. 실행
		Future<Integer> future = pool.submit(task);
		int result = future.get();	
		System.out.println("합 : " + result);
		// 4. 풀 닫기
		pool.shutdown();
	}

}





+ Recent posts