단일 스트림
병렬 스트림을 이해하기 위해 먼저 단일 스트림과 직접 스레드를 제어해 보는 예제를 알아보자.
로거 클래스 - 어떤 스레드에서 작업이 실행되는지 로그로 출력
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class MyLogger {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
public static void log(Object obj) {
String time = LocalTime.now().format(FORMATTER);
System.out.printf("%s [%9s] %s\n", time, Thread.currentThread().getName(), obj);
}
}각 작업당 1초 정도 소요되는 작업을 수행하는 HeavyJob 클래스
import util.MyLogger;
public class HeavyJob {
public static int heavyTask(int n) {
MyLogger.log("calculate " + n + " -> " + (n * 10));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return n * 10;
}
public static int heavyTask(int n, String name) {
MyLogger.log("[" + name + "] " + n + " -> " + (n * 10));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return n * 10;
}
}V1 - 단일 스트림
IntStream.rangeClosed(1, 8)을 사용해 1부터 8까지의 숫자 각각에 대해heavyTask()를 순서대로 수행한다.1초씩 걸리는 작업을 8번 순차로 호출하므로 약 8초가 소요된다.
또한 단일 스레드(
main스레드)에서 작업을 순차적으로 수행하기 때문에 로그에도main스레드만 표시된다.
V2 - 스레드 직접 사용
V1에서는 메인 스레드로 1에서 8의 범위를 모두 계산했다.각 스레드는 한번에 하나의 작업만 처리할 수 있다.
스레드를 사용해서 1에서 8을 처리하는 큰 단위의 작업을 더 작은 단위의 작업으로 분할하도록 해보자.
두 개의 스레드(
thread-1,thread-2)가 작업을 분할해서 처리하기 때문에 기존에 8초가 걸리던 작업을 4초로 줄일 수 있었다.하지만 이렇게 스레드를 직접 사용하면 스레드 수가 늘어나면 코드도 복잡해지고, 예외 처리, 스레드 풀 관리 등 추가로 관리해야 할 부분들이 생기는 문제가 있다.
V3 - 스레드 풀 사용
이번에는 자바가 제공하는 ExecutorService를 사용해서 더 편리하게 병렬 처리를 해보자.
V2와 마찬가지로 2개의 스레드가 병렬로 계산을 처리하므로 약 4초가 소요된다.Future로 반환값을 쉽게 받아올 수 있기 때문에 결과를 합산하는 과정이 더 편리해졌다.하지만 여전히 코드 레벨에서 분할 및 병합 로직을 직접 짜야 하고, 스레드 풀 생성과 관리도 개발자가 직접 해야 하는 문제가 있다.
Fork/Join 패턴
스레드는 한번에 하나의 작업만 처리할 수 있다. 따라서 하나의 큰 작업을 여러 스레드가 처리할 수 있는 작은 단위의 작업으로 분할(Fork) 해야 한다.
그리고 이렇게 분할한 작업을 각각의 스레드가 처리(Execute) 하고, 각 스레드의 분할된 작업 처리가 끝나면 분할된 결과를 하나로 모아야(Join) 한다.
이렇게 분할(Fork) → 처리(Execute) → 모음(Join) 의 단계로 이루어진 멀티스레딩 패턴을 Fork/Join 패턴이라고 한다.
이 패턴은 병렬 프로그래밍에서 매우 효율적인 방식으로, 복잡한 작업을 병렬적으로 처리할 수 있게 해준다.

자바는 Fork/Join 프레임워크를 제공하여 개발자가 이와 같은 패턴을 더 쉽게 구현할 수 있도록 지원한다.
Last updated