Executor → 자바가 제공하는 프레임 워크 / 스레드 풀, 스레드 관리, 생산자 소비자 문제 해결➡️ Runnable
void()➡️ Callable
concurrent에서 제공되는 기능V 임. → 값의 반환 가능throws Exception 예외가 선언되어 있음 → 해당 인터페이스를 구현하는 모든 메서드는 체크 예외인 Exception과 그 하위 예외를 모두 던질 수 있음ExecutorService es = new ThreadPoolExecutor(1,1,0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());corePoolSize: 스레드 풀에서 관리되는 기본 스레드 수maximumPoolSize: 스레드 풀에서 관리되는 최대 스레드 수keepAliveTime: 기본 스레드 수 초과해서 만들어진 스레드가 생존할 수 있는 대기 시간BlockingQueue: 작업을 보관 → 생산자, 소비자 문제를 해결 → 작업을 무한대로 저장 가능ExecutorService es = Executors.newFixedThreadPool(1); : 편의 코드Future는 전달한 작업의 미래 결과를 담고 있다고 생각하면 됨💡 왜 Future를 써야 할까?
- 요청스레드가 작업을 요청한 뒤 다른 작업 수행 가능
- 요청 스레드가 필요한 요청을 전부 한 다음에
get()을 통해 블로킹 상태로 대기하면서 결과를 받으면 된다.
boolean cancel(boolean mayInterruptIfRunning)mayInterruptIfRunning이 true면 중단true, 이미 완료되었거나 취소할 수 없으면 falseboolean isCancelled()boolean isDone()State state()RUNNING , SUCCESS , FAILED , CANCELLED)V get()InterruptedException : 대기 중인 스레드에 인터럽트 발생ExecutionException : 작업 계산 중 예외 발생V get(long timeout, TimeUnit unit)InterruptedException : 대기 중인 스레드에 인터럽트 발생ExecutionException : 작업 계산 중 예외 발생TimeoutException : 주어진 시간 내에 작업 완료되지 않음future.cancel(true) : Future를 취소 상태로 변경 → 작업이 실행중인 경우 인터럽트 발생, 작업 중단future.cancel(false) : Future를 취소 상태로 변경 → 이미 실행중인 작업은 중단하지 않음Future.get() 는 작업의 결과를 받을 수도, 예외를 받을 수도 있음Executor 인터페이스 확장, 작업의 제출과 제어 기능 추가 제공ExecutorService 인터페이스의 기본 구현체는 ThreadPoolExecutorexecute() - 반환값 x, submit() - 반환값 o, invokeAll(), invokeAny(), shutdown(), close() - ExecutorService 종료invokeAll() : 모든 Callable 작업을 제출, 모든 작업이 완료될 때까지 기다림invokeAny() : 가장 먼저 완료된 작업 결과 반환, 나머지는 전부 취소void shutdown() : 새로운 작업을 받지 않고 제출된 작업을 모두 완료 후 종료List<Runnable> shutdownNow() : 실행 중인 작업 모두 중단(인터럽트 발생) / 큐를 비우면서 큐에 담긴 작업을 꺼내 컬렉션으로 반환boolean isShutdown()boolean isTerminated()boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException : 서비스 종료 시 모든 작업이 완료될 때까지 대기close()shutdown()을 호출하고, 작업이 완료되거나 인터럽트가 발생할 때 까지 무한정 반복 대기➡️ 고정 스레드 풀 전략
ExecutorService es = Executors.newFixedThreadPool(2);
ThreadPoolExecutor es = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
newFixedThreadPool(nThreads)💡 요청은 제한 없이 무한정 받을 수 있는데, 처리하는 스레드 수는 한정적이라 사용자가 늘어날 수록 응답 속도가 떨어지게 됨
➡️ 캐시 스레드 풀 전략
ExecutorService es = Executors.newCachedThreadPool();
ThreadPoolExecutor es = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
newCachedThreadPool();SynchronousQueue ) → 생산자의 요청을 스레드 풀의 소비자가 직접 받아서 바로 처리💡사용자 증가에 따라 스레드 사용량도 늘어남 → CPU 메모리 사용량 증가 → 메모리 자원의 한계 때문에 적절한 시점에 시스템을 증설해야 함. 안그러면 다운됨
➡️ 사용자 정의 풀 전략
ExecutorService es = new ThreadPoolExecutor(100, 200, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000));
💡큐가 가득 차야 긴급 상황으로 인지됨 → 큐를 무한대 사이즈로 사용하면 큐가 가득차지 않아 무한대의 작업을 처리해야 하는 상황 발생
➡️ AbortPolicy
ThreadPoolExecutor es = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadPoolExecutor.AbortPolicy());
RejectedExecutionException 예외 던짐➡️ DiscardPolicy
ThreadPoolExecutor es = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadPoolExecutor.DiscardPolicy());
➡️ CallerRunsPolicy
ThreadPoolExecutor es = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
➡️ 사용자 정의
RejectedExecutionHandler 인터페이스 구현