-
[Java 기초] 멀티스레드 - 2카테고리 없음 2019. 5. 15. 20:50
1. 데몬 스레드
데몬 스레드는 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드입니다. 즉, 백그라운드상태로 대기하고 있다가 특정 조건이 만족되면 작업을 수행하고 다시 대기상태로 돌아가는 스레드를 말합니다. 만일, 주 스레드가 종료된다면 백그라운드로 돌고있던 데몬스레드도 자연스럽게 같이 종료되게 됩니다.
데몬 스레드 생성을 위해서는 아래와 같이 setDaemon(true)을 선언해주면 됩니다.
public class AutoSaveThread extends Thread { public void save() { System.out.println("save"); } @Override public void run() { while(true) { try { Thread.sleep(1000); //1초를 쉰다. 즉, 1초 후에 아래의 save(); 가 실행됨. } catch (InterruptedException e) { break; } save(); } } }
public static void main(String[] args) { AutoSaveThread thread = new AutoSaveThread(); // 자동 저장을 위한 스레드 선언 thread.setDaemon(true); // 데몬스레드 사용 선언 thread.start(); try { Thread.sleep(3000); // 메인 스레드가 3초 쉬는 동안 데몬 스레드는 3초간 일을한다. } catch (InterruptedException e) { } System.out.println("Main thread is Terminated"); }
위의 예제에서 알 수 있듯이 main 스레드가 sleep 상태에 있더라도 백그라운드로 작업하는 데몬 스레드는 1초 쉬고 일하고, 1초 쉬고 일하고, 1초 쉬고 일하고 메인스레드가 종료됨과 동시에 데몬스레드도 종료상태가 되게 됩니다.
2. 스레드 그룹
스레드를 개별적으로 선언해서 사용하게 되면 스레드의 수가 늘어남에 따라 관리가 힘들어지게 됩니다. 예를들어 1000개의 스레드 중에 500개를 종료시키고 싶다면 500개를 하나씩 종료시켜야 합니다. 따라서, 이런 문제를 방지하고자 스레드 그룹이 생겼습니다.
대표적인 스레드 그룹은 system 스레드 그룹인데, 이는 JVM이 실행되면 JVM 운영에 필요한 스레드들을 생성해서 system 스레드 그룹에 포함시키게 됩니다. 그리고 system의 하위 스레드 그룹에 main을 만들고 메인 스레드를 main 스레드 그룹에 포함시킵니다. 명시적으로 스레드를 스레드 그룹에 포함시키지 않으면 자동으로 자신을 생성한 스레드와 같은 스레드 그룹에 묶이게 됩니다.
1) 스레드 그룹 생성
스레드 그룹의 생성은 간단한데, 이름처럼 ThreadGroup 객체를 만들면 됩니다.
ThreadGroup group1 = new ThreadGroup(String name); ThreadGroup group2 = new ThreadGroup(ThreadGroup parent, String name);
group2에서 보이는 대로 parent 그룹을 인자로 주게 되면, 하위 그룹으로 묶이게 됩니다. 그리고 group1처럼 parent 인자를 주지 않으면 현재 스레드가 속한 그룹의 하위 그룹으로 묶이게 됩니다.
2) 스레드 그룹의 메서드
메서드명 설명 interrupt() 현재 그룹의 모든 스레드들을 interrupt한다. 즉, 중지상태로 만듦. destroy() 현재 그룹 및 하위 그룹 모두 삭제 activeCount() 현재 그룹과 하위 그룹에서 작업중인 스레드의 수 출력 activeGroupCount() 작업중인 그룹의 수 출력 checkAccess() 스레드 그룹에 대한 변경 권한이 있는지 체크 list() 현재 그룹 및 하위 그룹 리스트 출력 3. 스레드 풀
출처: https://palpit.tistory.com/732
스레드의 수가 계속해서 증가하면서 동시에 처리할 수 있는 양이 많아지면 그만큼 CPU와 같은 자원소모도 커지게 됩니다. 이러한 문제를 막아내고자 스레드풀이라는 개념이 탄생했습니다.
스레드풀(Thread Pool)은 말 그대로 스레드들을 담는 공간을 의미합니다. 즉, 스레드풀이라는 공간에 일정량의 스레드를 배치해 두는 것이죠. 그리고 어떤 작업이 스레드를 필요로 하면 스레드 풀에서 가져다 쓰면 됩니다. 그리고 만일 작업량이 많아 스레드 풀에 스레드가 비어있다면 누군가가 스레드를 스레드 풀에 반납하길 기다렸다가 스레드가 반납되면 그 스레드로 작업을 하는 것입니다.
1) 스레드 풀 생성
메서드명 초기 스레드 수 코어 스레드 수 최대 스레드 수 newCachedThreadPool() 0 0 Integer.MAX_VALUE newFixedThreadPool(int nThreads) 0 nThreads nThreads 위의 표에서 초기 스레드 수는 ExecutorService 객체가 생성될 때 만들어지는 스레드의 수를 의미하고, 코어 스레드는 스레드 풀이 가지고 있어야 할 최소 스레드 갯수를 의미하며, 최대 스레드 수는 스레드 풀이 가질 수 있는 스레드의 최대 갯수를 의미합니다. 스레드풀을 선언하는 방법은 아래와 같습니다.
// 방법 1. newCachedThreadPool ExecutorService executorService1 = Executors.newCachedThreadPool(); // 방법 2. newFixedThreadPool ExecutorService executorService2 = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessros() // CPU 코어의 수만큼 최대 스레드를 줌 ); // 방법 3. ThreadPoolExecutor 사용.(위의 방법 1, 2 모두 ThreadPoolExecutor를 상속해서 사용함) ExecutorService threadPool = new ThreadPoolExecutor( 5, // 코어 스레드 개수 100, // 최대 스레드 개수 100L, // 놀고 있는 시간 TimeUnit.SECONDS, // 시간 단위를 second로 설정 new SynchronousQueue<Runnable>() // 작업 큐 );
2) 스레드 풀 종료
// 방법 1. 현재 처리중인 작업 + 작업 큐에 대기하고 있는 모든 작업 처리 후 스레드풀 종료 executorService.shutdown(); // 방법 2. 현재 작업 처리 중인 스레드를 중지시킨 후 스레드 풀 종료 executorService.shutdownNow();
3) 작업 생성
스레드에서 하나의 작업은 Runnable 또는 Callable 구현 클래스로 표현한다. 그리고 스레드풀의 스레드는 작업 큐에서 Runnable 또는 Callable 객체를 가져와 run()과 call() 메소드를 실행한다.
// Runnable Runnable runnableTask = new Runnable(){ @Override public void run(){ // 작업할 내용 } } //Callable Callable<T> callableTask = new Callable<T>() { @Override public T call() throws Exception { //작업내용 return T; } }
4) 작업 처리 요청
작업 처리 요청이란, 말 그대로 작업 큐에 Runnable 또는 Callable 객체를 넣는 행위를 의미한다.
리턴타입 메서드 설명 void execute(Runnable cmd) Runnable 객체를 작업큐에 저장시킴 Future<?> submit(Runnable task) Runnable 또는 Callable 객체를 작업 큐에 저장 Future<V> submit(Runnable task, V result) Future<V> submit(Callable<V> task) execute()와 submit()의 차이점은
1. execute()는 리턴값이 없고, submit()은 Future를 리턴한다.
2. execute()는 예외 발생시 스레드가 종료되고 스레드풀은 스레드를 재생성하며, submit()은 스레드가 종료되지 않고 다음 작업을 위해 재사용된다.
따라서, 오버헤드를 줄이기 위해서 submit()의 사용을 권장한다.