Fork join pool
java 1.7 부터 지원한다
많은 양의 데이터를 작업하기 용이한 크기로 나누어 여러 thread에서 데이터를 처리한다
데이터를 처리함에 유휴 thread가 최대한 존재하지 않도록 하기 위함이다
예제에 사용된 전체 소스 코드는 하단의 Repository 링크를 참고하면 된다
ForkJoinPool
작업을 실행할 thread pool
작업 실행 및 관리 method
execute
ForkJoinTask interface를 구현한 객체를 매개 변수로 전달 받으며 작업 실행에 대한 결과를 반환 받을 수 없다
submit
ForkJoinTask interface를 구현한 객체를 매개 변수로 전달 받으며 작업 실행에 대한 결과를 반환 받을 수 있다
ForkJoinTask
fork join pool에 작업을 추가하기 위해서는 ForkJoinTask을 상속한 class를 사용 하여야 한다
RecursiveAction
ForkJoinTask 상송한 class이다
작업의 결과를 반환하지 않는다
RecursiveTask
ForkJoinTask 상속한 class이다
작업의 결과를 반환한다
예제 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class MaxIntegerTask extends RecursiveTask<Integer> {
private List<Integer> list;
public MaxIntegerTask(List<Integer> list) {
this.list = list;
}
@Override
protected Integer compute() {
String threadName = Thread.currentThread().getName();
System.out.printf("START: [%s]\n", threadName);
int listSize = this.list.size();
if (listSize > 2) { // 분할
int subSize0 = (int) Math.floor(listSize / 2f);
int subSize1 = (int) Math.ceil(listSize / 2f);
List<Integer> subList0 = this.list.subList(0, subSize0);
List<Integer> subList1 = this.list.subList(listSize - subSize1, listSize);
MaxIntegerTask subTask0 = new MaxIntegerTask(subList0);
MaxIntegerTask subTask1 = new MaxIntegerTask(subList1);
subTask0.fork();
subTask1.fork();
Integer result0 = subTask0.join();
Integer result1 = subTask1.join();
return Math.max(result0, result1);
} else { // 분할하지 않음
if (this.list.size() == 1) {
return this.list.get(0);
} else {
return Math.max(this.list.get(0), this.list.get(1));
}
}
}
}
Integer list중에 가장 큰 수를 구하는 작업이다
list의 길이가 2개 이상인 경우에 분할하고, 1개인 경우에는 그 Integer를 반환하고 2개인 경우에는 둘중에 큰 수를 반환한다
1
2
3
4
5
6
7
8
9
10
11
public class ForkJoinPoolMain {
public static void main(String[] args) throws Exception {
ForkJoinPool forkJoinPool = new ForkJoinPool(2);
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 12, 6, 7, 8, 9, 10);
MaxIntegerTask task = new MaxIntegerTask(list);
ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(task);
Integer result = forkJoinTask.get();
System.out.println(result);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
START: [ForkJoinPool-1-worker-3]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-3]
START: [ForkJoinPool-1-worker-1]
START: [ForkJoinPool-1-worker-3]
START: [ForkJoinPool-1-worker-3]
START: [ForkJoinPool-1-worker-1]
12
ForkJoinPool에 thread를 2개로 설정한 후에 작업을 할당 하면 2개의 thread로 분할 작업 하게 된다
결론
thread를 이용한 병렬 처리의 목적은 많은 요소를 짧은 시간에 효율적으로 처리하고자 사용한다
특히 fork join pool인 경우에는 유휴 thread가 최소한으로 발생 하도록 하는 방법이므로 분할한 작업들이 최대한 균일한 작업 시간이 소요 할 수 있는 경우에 fork join pool에서 효율이 증가한다