[자바의 정석 2권] fork & join 프레임웍(1) - Fork&Join 프레임웍이란?
1) fork & join 프레임웍이란?
- 10년 전까지만 해도 CPU의 속도는 매년 거의 2배씩 빠르게 향상되어 왔다.
그러나 이제 그 한계에 도달하여 속도보다는 코어의 개수를 늘려서
CPU의 성능을 향상시키는 방향으로 발전해가고 있다.
- 이러한 하드웨어의 변화에 발맞춰 프로그래밍도 멀티 코어를 잘 활용할 수 있는
멀티쓰레드 프로그래밍이 점점 더 중요해지고 있다.
- 그래서 JDK1.7부터 'fork&join 프레임웍'이 추가되었고,
이 프레임웍은 하나의 작업을 작은 단위로 나눠서 여러 쓰레드가 동시에 처리하는 것을
쉽게 만들어준다.
- 먼저 수행할 작업에 따라 RecursiveAction과 RecursiveTask,
두 클래스 중에서 하나를 상속받아 구현해야 한다.
RecursiveAction 반환값이 없는 작업을 구현할 때 사용
RecursiveTask 반환값이 있는 작업을 구현할 때 사용
- 두 클래스 모두 compute()라는 추상 메서드를 가지고 있는데,
우리는 상속을 통해 추상 메서드를 구현하기만 하면 된다.
public abstract class RecursiveAction extends ForkJoinTask<Void> {
...
protected abstract void compute(); // 상속을 통해 이 메서드를 구현해야 한다.
...
}
public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
...
protected abstract V compute(); // 상속을 통해 이 메서드를 구현해야 한다.
...
}
- 예를 들어, 1부터 n까지의 합을 계산한 결과를 돌려주는 작업의 구현은 다음과 같이 한다.
class SumTask extends RecursiveTask<Long> {
long from, to;
SumTask(long from, long to){
this.from = from;
this.to = to;
}
public Long compute() {
// 처리할 작업을 수행하기 위한 문장을 넣는다.
}
}
- 그 다음에는 쓰레드풀과 수행할 작업을 생성하고, invoke()로 작업을 시작한다.
쓰레드를 시작할 때 run()이 아니라 start()를 호출하는 것처럼,
fork&join 프레임웍으로 수행할 작업도 compute()가 아닌 invoke()로 시작한다.
ForkJoinPool pool = new ForkJoinPool(); // 쓰레드 풀을 생성
SumTask task = new SumTask(from, to); // 수행할 작업을 생성
Long result = pool.invoke(task); // invoke()를 호출해서 작업을 시작
- ForkJoinPool은 fork&join 프레임웍에서 제공하는 쓰레드 풀(thread pool)로,
지정된 수의 쓰레드를 생성해서 미리 만들어 놓고 반복해서 재사용할 수 있게 한다.
그리고 쓰레드를 반복해서 생성하지 않아도 된다는 장점과
너무 많은 쓰레드가 생성되어 성능이 저하되는 것을 막아준다는 장점이 있다.
- 쓰레드 풀은 쓰레드가 수행해야 하는 작업이 담긴 큐를 제공하며,
각 쓰레드는 자신의 작업 큐에 담긴 작업을 순서대로 처리한다.