간략하게 설명하자면
ExecutorService는 java.util.concurrent 패키지에서 제공하는 인터페이스로
Executor 인터페이스를 상속받는다.

(Executor, Thread, Thread Pool) 설명하겠다.
-Executor란
동시에 여러 요청을 처리하는 경우 계속 새로운 Thread를 만들기보단
Thread를 미리 생성하고 재사용하기 위한 Thread Pool이 존재하는데
이 Thread Pool의 구현을 위한 Interface가 Executor다.
-Thread
Thread란 프로세스 내에서 실제로 작업을 수행하는 주체로
JAVA에서는 Thread를 운영체제의 자원으로 사용하며
이러한 Thread를 계속하여 생성하면 메모리 사용량이 계속 증가하므로
서버가 다운될 확률이 존재한다.
Thread는 크게 작업의 등록과 실행으로 나눈다.
위의 상황을 방지하기 위해서 Thread Pool을 사용한다.
-Thread Pool
Thread Pool은 Thread의 계속적인 증가를 막기 위해서
Thread를 제한된 개수만큼 정해두고 작업 큐에 들어오는 작업들을 하나씩
Thread가 맡아서 처리한다.
작업 처리가 끝난 Thread는 다시 작업 큐에 들어오는 작업을 처리한다.

결과적으로 위의 Thread Pool의 구현을 위한 인터페이스가 Executor다.
Executor 인터페이스는 SOLID원칙의 ISP(인터페이스 분리 원칙)에 맞게
등록된 작업(Runnable)을 실행하는 책임만을 가진다.
즉 전달받은 작업을 실행하는 메소드(execute)만 가진다.

ExecutorService 인터페이스는 Executor를 상속받으며
작업 등록(Callable,Runnable)뿐만 아니라 실행을 위한 책임도 가진다.
ExecutorService의 메소드 종류
shutdown, shutdownNow, submit(Callable), submit(Runnable)등이 있다.
Runnable 인터페이스는 어떤 객체도 반환하지 않으며 예외가 없다.
반면 Callable 인터페이스는 제네릭을 사용해 특정 타입의 객체를 리턴받을수 있으며
Call()메소드 실행중 예외를 발생시킬 수 있다.
즉 Runnable, Callable 두 인터페이스의 차이는 작업의 결과값 반환 유무이다.
Future 인터페이스는 비동기 계산의 결과를 나타내며 계산이 완료되었는지 확인하고
완료될때까지 기다리고 계산 결과를 검색하는 메서드가 제공된다.
결과는 get계산이 완료된 경우에만 메서드를 사용하여 검색할 수 있으며
cancel을 통해 실행을 취소할 수 있다.
