×

Cách sử dụng fork/join framework trong Java?

Fork/Join Framework trong Java là một framework được thiết kế để tận dụng lợi thế của việc lập trình đa luồng, đặc biệt là trên các hệ thống đa nhân, thông qua mô hình "chia để trị". Mục tiêu chính của framework này là giúp phát triển các ứng dụng đa luồng một cách dễ dàng hơn, nhanh chóng và hiệu quả. Nó được giới thiệu trong Java 7, nằm trong gói java.util.concurrent.

Tạo một lớp làm việc (task)

Để sử dụng Fork/Join Framework, bạn cần tạo một lớp làm việc (task) bằng cách kế thừa từ một trong hai lớp RecursiveAction (cho các tác vụ không trả về giá trị) hoặc RecursiveTask<V> (cho các tác vụ trả về giá trị của loại V).

Chia tác vụ thành các tác vụ nhỏ hơn

Trong lớp làm việc của bạn, bạn sẽ cần phải định nghĩa phương thức compute(), nơi bạn sẽ chia tác vụ lớn của mình thành các tác vụ nhỏ hơn, và cuối cùng là "fork" (chia nhỏ) và "join" (gộp lại) chúng.

Sử dụng ForkJoinPool để thực thi

Để thực thi các tác vụ của bạn, bạn sẽ cần sử dụng một instance của ForkJoinPool, đó là một loại đặc biệt của ExecutorService được tối ưu hóa cho Fork/Join Framework.

Ví dụ

Giả sử bạn muốn tính tổng của một mảng số nguyên sử dụng Fork/Join Framework.

Bước 1: Tạo lớp RecursiveTask.

import java.util.concurrent.RecursiveTask;

public class SumTask extends RecursiveTask<Long> {
    private final int[] array;
    private final int start;
    private final int end;
    private static final int THRESHOLD = 100; // Điểm ngưỡng để chia tác vụ

    public SumTask(int[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long sum = 0;
        if (end - start < THRESHOLD) {
            // Tính toán trực tiếp
            for (int i = start; i < end; i++) {
                sum += array[i];
            }
        } else {
            // Chia tác vụ
            int mid = start + (end - start) / 2;
            SumTask leftTask = new SumTask(array, start, mid);
            SumTask rightTask = new SumTask(array, mid, end);
            
            leftTask.fork(); // Thực hiện tác vụ con một cách đồng thời
            sum += rightTask.compute(); // Thực hiện tác vụ con trên cùng luồng và chờ kết quả
            sum += leftTask.join(); // Đợi kết quả từ tác vụ con và gộp kết quả
        }
        return sum;
    }
}

Bước 2: Sử dụng ForkJoinPool để thực thi tác vụ.

import java.util.concurrent.ForkJoinPool;

public class SumArray {
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        int[] array = {1, 2, 3, 4, 5, ...}; // Ví dụ về mảng số nguyên
        SumTask task = new SumTask(array, 0, array.length);
        
        long result = pool.invoke(task); // Thực thi và chờ kết quả
        System.out.println("Tổng: " + result);
    }
}

Trong ví dụ này, SumTask là một RecursiveTask được tạo ra để tính tổng của một mảng. Nếu kích thước của phần mảng được xử lý nhỏ hơn một ngưỡng nhất định (THRESHOLD), nó sẽ tính tổng trực tiếp. Nếu lớn hơn, nó sẽ chia mảng thành hai phần, tạo ra hai tác vụ mới và sử dụng phương thức fork()join() để thực hiện đồng thời và gộp kết quả. ForkJoinPool được sử dụng để thực thi tác vụ và chờ kết quả.

Comments