- 자바 5부터는 동시성 컬렉션인 java.util.concurrent 라이브러리와 실행자(Executor) 프레임워크를 지원했다.
- 자바 7부터는 고성능 병렬 분해 프레임워크인 포크-조인 패키지를 추가했다.
- 포크조인(ForkJoin) 프레임워크는 병렬 처리를 위한 모델이고 분할 정복 알고리즘을 통해서 재귀적으로 처리
- 자바 8부터는 parallel 메서드만 한 번 호출하면 파이프라인을 병렬 실행할 수 있는 스트림을 지원했다.
- 병렬 스트림은 요소들을 병렬 처리하기 위해 포크조인(ForkJoin) 프레임워크를 사용
- 이처럼 자바로 동시성 프로그램을 작성하기가 점점 쉬워지고는 있지만, 이를 올바르고 빠르게 작성하는 일은 여전히 어려운 작업이다.
병렬 처리(Parallel Operation)란 멀티 코어 CPU 환경에서 하나의 작업을 분할해서 각 코어가 병렬적으로 처리하는 것,
병렬 처리의 목적은 작업 처리 시간을 줄이기 위한 것
- 포크 단계에서 전체 데이터를 서브 데이터로 분리한다.
- 그 후 서브 데이터를 멀티 코어에서 병렬 처리
- 조인 단계에서는 서브 결과를 결합해서 최종 결과를 만들어 낸다.
- https://www.baeldung.com/java-fork-join
- https://warpgate3.tistory.com/entry/ForkJoin-Framework-in-Java
public static void main(String[] args) {
System.out.println("Normal...");
IntStream range = IntStream.rangeClosed(1, 10);
range.forEach(System.out::println);
System.out.println();
System.out.println("Parallel...");
IntStream range2 = IntStream.rangeClosed(1, 10);
range2.parallel().forEach(System.out::println);
}
Normal...
1
2
3
4
5
6
7
8
9
10
Parallel...
7
6
2
9
1
3
10
8
4
5
public static void main(String[] args) {
System.out.println("Normal...");
IntStream range = IntStream.rangeClosed(1, 10);
range.forEach(x ->
System.out.println("Thread : " + Thread.currentThread().getName() + ", value: " + x));
System.out.println();
System.out.println("Parallel...");
IntStream range2 = IntStream.rangeClosed(1, 10);
range2.parallel().forEach(x ->
System.out.println("Thread : " + Thread.currentThread().getName() + ", value: " + x));
}
Normal...
Thread : main, value: 1
Thread : main, value: 2
Thread : main, value: 3
Thread : main, value: 4
Thread : main, value: 5
Thread : main, value: 6
Thread : main, value: 7
Thread : main, value: 8
Thread : main, value: 9
Thread : main, value: 10
Parallel...
Thread : main, value: 7
Thread : main, value: 6
Thread : main, value: 9
Thread : ForkJoinPool.commonPool-worker-5, value: 8
Thread : main, value: 10
Thread : ForkJoinPool.commonPool-worker-3, value: 3
Thread : ForkJoinPool.commonPool-worker-5, value: 2
Thread : ForkJoinPool.commonPool-worker-3, value: 5
Thread : ForkJoinPool.commonPool-worker-5, value: 1
Thread : ForkJoinPool.commonPool-worker-3, value: 4
public static void work(int value) {
try {
Thread.sleep(100);
} catch(InterruptedException e) {}
}
public static long sequenceTest(List<Integer> list) {
long start = System.nanoTime();
list.stream().forEach(ParallelStream::work);
long end = System.nanoTime();
long runTime = end - start;
return runTime;
}
public static long parallelTest(List<Integer> list) {
long start = System.nanoTime();
list.stream().parallel().forEach(ParallelStream::work);
long end = System.nanoTime();
long runTime = end - start;
return runTime;
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
// 순차 스트림 처리 시간
long timeSequence = sequenceTest(list);
// 병렬 스트림 처리 시간
long timeParallel = parallelTest(list);
if (timeSequence < timeParallel) {
System.out.println("결과: 순차 처리가 더 빠름");
} else {
System.out.println("결과: 병렬 처리가 더 빠름");
}
}
결과: 병렬 처리가 더 빠름
public static void work(int value) {
try {
Thread.sleep(5);
} catch(InterruptedException e) {}
}
// ...
결과: 순차 처리가 더 빠름
- 계산도 올바로 수행하고 성능도 빨라질 거라는 확신 없이는 스트림 파이프라인 병렬화는 시도조차 하지 말라.
- 스트림을 잘못 병렬화하면 프로그램을 오동작하게 하거나 성능을 급격히 떨어뜨린다.
- 즉, 계산도 정확하고 성능도 좋아졌음이 확실해졌을 때만 스트림 병렬화를 사용하라.
https://www.baeldung.com/java-fork-join
https://warpgate3.tistory.com/entry/ForkJoin-Framework-in-Java
https://mkyong.com/java8/java-8-parallel-streams-examples/
http://www.yes24.com/Product/Goods/15651484