Sobes.tech
Middle+
383

Šta je Fork/Join okvir i kako se koristi u Javi?

Одговор од АИ

sobes.tech АИ

Fork/Join okvir je specijalizovana implementacija okvira Executor, namenjena za efikasno paralelno razbijanje zadataka koji se mogu rekurzivno razbiti na manje podzadatke, a zatim spojiti (join) njihove rezultate. Osnovan je na principu "podeli i osvoji".

Ključne komponente:

  • ForkJoinPool: Bazen niti koji upravlja izvršavanjem zadataka. Koristi mehanizam "work-stealing", gde neaktivne niti mogu "ukrasti" zadatke od drugih zauzetih niti.
  • ForkJoinTask: Apstraktna klasa koja predstavlja zadatak koji se može izvršiti u ovom okviru. Ima dve podklase:
    • RecursiveAction: Zadatak koji ne vraća rezultat.
    • RecursiveTask<V>: Zadatak koji vraća rezultat tipa V.

Upotreba:

  1. Kreira se klasa koja nasleđuje RecursiveAction ili RecursiveTask.
  2. Prepisuje se metoda compute(). U ovoj metodi se opisuje logika:
    • Ako je zadatak dovoljno mali (manji od određenog praga), izvršava se direktno.
    • U suprotnom, zadatak se razbija na podzadatke koji se pokreću asinhrono metodom fork().
    • Čeka se završetak podzadatka metodom join() i njihovi rezultati se spajaju.
  3. Kreira se instanca ForkJoinPool.
  4. Zadatak se predaje u bazen koristeći invoke() ili submit().

Primer:

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;

class SumArrayTask extends RecursiveTask<Long> {
    private final long[] array;
    private final int start;
    private final int end;
    private static final int THRESHOLD = 1000; // Prag

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

    @Override
    protected Long compute() {
        if (end - start <= THRESHOLD) {
            // Direktno računanje za male opsege
            long sum = 0;
            for (int i = start; i < end; i++) {
                sum += array[i];
            }
            return sum;
        } else {
            // Podela zadatka
            int mid = start + (end - start) / 2;
            SumArrayTask leftTask = new SumArrayTask(array, start, mid);
            SumArrayTask rightTask = new SumArrayTask(array, mid, end);

            // Asinhrono izvršavanje podzadatka
            leftTask.fork();
            Long rightResult = rightTask.compute();
            Long leftResult = leftTask.join();

            // Spajanje rezultata
            return leftResult + rightResult;
        }
    }
}

// Upotreba u glavnom kodu
// long[] data = new long[10000]; // Početni podaci
// // Popunjavanje podataka
// ForkJoinPool pool = new ForkJoinPool();
// long sum = pool.invoke(new SumArrayTask(data, 0, data.length));
// pool.shutdown(); // Zatvaranje bazena nakon upotrebe

Prednosti:

  • Automatsko upravljanje bazenom niti.
  • Efikasno raspoređivanje opterećenja zahvaljujući work-stealing-u.
  • Poboljšana performansa za zadatke tipa "podeli i osvoji".

Nedostaci:

  • Nije pogodan za sve tipove paralelnih zadataka.
  • Može biti složeniji za implementaciju u poređenju sa drugim pristupima za jednostavne zadatke.