Middle+
Kas yra Fork/Join rėmas ir kaip jis naudojamas Java?
sobes.tech AI
Atsakymas iš AI
„Fork/Join“ rėmas — tai specializuota „Executor“ rėmo realizacija, skirta efektyviam užduočių paralelizavimui, kurios gali būti rekursiškai suskirstytos į mažesnes užduotis ir vėliau sujungtos (join) jų rezultatus. Jis grindžiamas principu „skaldyk ir valdyk“ (divide and conquer).
Pagrindiniai komponentai:
ForkJoinPool: srautų baseinas, kuris valdo užduočių vykdymą. Jis naudoja „work-stealing“ mechanizmą, kai laukiančios srovės gali „įsilaužti“ į kitų užimtų srovių užduotis.ForkJoinTask: abstrakti klasė, atstovaujanti užduotį, kuri gali būti vykdoma šiame rėme. Ji turi du tipus:RecursiveAction: užduotis, kuri negrąžina rezultato.RecursiveTask<V>: užduotis, kuri grąžina rezultatą tipoV.
Naudojimas:
- Sukuriamas klasės, paveldinčios
RecursiveActionarbaRecursiveTask. - Perrašomas
compute()metodas. Šiame metode aprašoma logika:- Jei užduotis pakankamai maža (mažesnė už tam tikrą slenkstį), ji vykdoma tiesiogiai.
- Kitaip, užduotis padalijama į mažesnes užduotis, kurios vykdomos asinchroniškai
fork()metodu. - Laukiama ir gaunami rezultatų
join()metodu ir jie sujungiami.
- Sukuriamas
ForkJoinPoolegzempliorius. - Užduotis pateikiama į baseiną naudojant
invoke()arbasubmit()metodus.
Pavyzdys:
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; // slenkstis
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) {
// tiesioginis skaičiavimas mažose diapazonuose
long sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
return sum;
} else {
// užduoties padalijimas
int mid = start + (end - start) / 2;
SumArrayTask leftTask = new SumArrayTask(array, start, mid);
SumArrayTask rightTask = new SumArrayTask(array, mid, end);
// asinchroninis mažesnių užduočių vykdymas
leftTask.fork();
// vykdymas dešinės užduoties dabartiniame arba kitame prieinamame sraute
Long rightResult = rightTask.compute();
// laukia ir gauna kairės užduoties rezultatą
Long leftResult = leftTask.join();
// rezultatų sujungimas
return leftResult + rightResult;
}
}
}
// Naudojimas pagrindiniame kode
// long[] data = new long[10000]; // pradiniai duomenys
// // užpildyti duomenis
// ForkJoinPool pool = new ForkJoinPool();
// long sum = pool.invoke(new SumArrayTask(data, 0, data.length));
// pool.shutdown(); // uždaryti baseiną po naudojimo
Privalumai:
- Automatinis srautų valdymas.
- Efektyvus apkrovos paskirstymas naudojant work-stealing.
- Pagerintas našumas „skaldyk ir valdyk“ užduotims.
Trūkumai:
- Netinka visų tipų paraleliniams užduotims.
- Gali būti sudėtingesnis įgyvendinimas palyginti su kitomis paprastomis metodikomis.