Forkjoinpool
De klasse ForkJoinPool in Java voor het werken met het Fork/Join-framework is precies hiervan de realisatie. Het biedt mechanismen voor het beheren van taken die kunnen worden opgesplitst in kleinere subtaken en parallel uitgevoerd kunnen worden.
Main.java
1ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinPool is gebaseerd op het concept van twee basisacties: fork en join. Fork is een actie waarbij een grote taak wordt opgesplitst in meerdere kleinere subtaken die parallel uitgevoerd kunnen worden. Join is het proces waarbij de resultaten van deze subtaken worden samengevoegd tot het resultaat van de oorspronkelijke taak.
Casestudy
Stel je voor dat je een enorme dataset moet analyseren die kan worden opgedeeld in verschillende kleinere sets. Als je elke dataset afzonderlijk verwerkt en vervolgens de resultaten samenvoegt, kun je de verwerking aanzienlijk versnellen, vooral op multiprocessorsystemen.
Gebruik van ForkJoinPool
Er zijn 2 klassen om taken in te implementeren, namelijk RecursiveTask en RecursiveAction. Beide vereisen dat de abstracte methode compute() wordt geïmplementeerd. In RecursiveTask geeft de methode compute() een waarde terug, terwijl in RecursiveAction de methode compute() void teruggeeft.
Main.java
12345678class ExampleTask extends RecursiveTask<String> { @Override protected String compute() { // code return null; } }
Wanneer we erven van een RecursiveTask, moeten we ervoor zorgen dat we het gegevenstype specificeren dat onze compute()-methode zal teruggeven met deze syntaxis: RecursiveTask<String>.
Main.java
1234567class ExampleAction extends RecursiveAction { @Override protected void compute() { // code } }
Hier is het tegenovergestelde het geval, we hoeven het type niet expliciet te specificeren in RecursiveAction, omdat onze methode niets zal teruggeven en alleen de taak zal uitvoeren.
Een taak starten
Overigens kunnen we een taak starten voor uitvoering zonder zelfs maar gebruik te maken van ForkJoinPool, door simpelweg de methoden fork() en join() te gebruiken.
Het is belangrijk op te merken dat de methode fork() de taak naar een willekeurige thread stuurt. De methode join() wordt gebruikt om het resultaat op te halen.
Main.java
12345public static void main(String[] args) { ExampleTask simpleClass = new ExampleTask(); simpleClass.fork(); System.out.println(simpleClass.join()); }
Belangrijkste methoden van ForkJoinPool
invoke(): Start een taak in de pool en wacht tot deze voltooid is. Geeft het resultaat van de taak terug;submit(): Dient een taak in bij de pool, maar blokkeert de huidige thread niet tijdens het wachten op voltooiing van de taak. Kan worden gebruikt om taken in te dienen en hunFuture-objecten op te halen;execute(): Voert een taak uit in de pool, maar geeft geen resultaat terug en blokkeert de huidige thread niet.
Hoe kunnen we een taak starten met behulp van ForkJoinPool, heel eenvoudig!
Main.java
12345public static void main(String[] args) { ExampleAction simpleClass = new ExampleAction(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); }
Maar wat is het verschil tussen uitvoeren met fork(), join() en via de ForkJoinPool klasse?
Het is heel eenvoudig! Bij gebruik van de eerste methode met behulp van de fork(), join() methoden, wordt de taak gestart in dezelfde thread waarin deze methoden zijn aangeroepen, waardoor deze thread wordt geblokkeerd, terwijl met behulp van de ForkJoinPool klasse een thread uit de pool wordt toegewezen en deze taak in die thread wordt uitgevoerd zonder de hoofdthread te blokkeren.
Laten we dit nader bekijken; stel dat we de volgende implementatie hebben:
Main.java
12345678class ExampleRecursiveTask extends RecursiveTask<String> { @Override protected String compute() { System.out.println("Thread: " + Thread.currentThread().getName()); return "Wow, it works!!!"; } }
En we willen deze code uitvoeren met behulp van fork() en join(). Laten we bekijken wat er op de console wordt afgedrukt en welke thread deze taak zal uitvoeren.
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); simpleClass.fork(); System.out.println(simpleClass.join()); } }
En we krijgen deze uitvoer op de console:
Thread: main
Wow, it works!!!
Laten we nu bekijken wat er gebeurt als we uitvoeren met ForkJoinPool:
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); } }
En we komen tot deze conclusie:
Thread: ForkJoinPool-1-worker-1
Wow, it works!!!
En zoals te zien is het verschil dat bij gebruik van de eerste methode de taak wordt uitgevoerd in dezelfde thread die deze taak heeft aangeroepen (Main thread). Maar als we de tweede methode gebruiken, wordt de thread uit de ForkJoinPool threadpool gehaald en wordt de hoofdthread die deze logica heeft aangeroepen niet geblokkeerd en gaat verder!
Hoe Fork/Join in Code te Implementeren
De eenvoudigste manier om dit uit te leggen is via een video, in plaats van je 50-80 regels code te geven en deze punt voor punt toe te lichten.
ForkJoinPool is effectief voor taken die eenvoudig kunnen worden opgesplitst in kleinere subtaken. Als de taken echter te klein zijn, levert het gebruik van ForkJoinPool mogelijk geen significante prestatieverbetering op.
Bedankt voor je feedback!
Vraag AI
Vraag AI
Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.
Awesome!
Completion rate improved to 3.33
Forkjoinpool
Veeg om het menu te tonen
De klasse ForkJoinPool in Java voor het werken met het Fork/Join-framework is precies hiervan de realisatie. Het biedt mechanismen voor het beheren van taken die kunnen worden opgesplitst in kleinere subtaken en parallel uitgevoerd kunnen worden.
Main.java
1ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinPool is gebaseerd op het concept van twee basisacties: fork en join. Fork is een actie waarbij een grote taak wordt opgesplitst in meerdere kleinere subtaken die parallel uitgevoerd kunnen worden. Join is het proces waarbij de resultaten van deze subtaken worden samengevoegd tot het resultaat van de oorspronkelijke taak.
Casestudy
Stel je voor dat je een enorme dataset moet analyseren die kan worden opgedeeld in verschillende kleinere sets. Als je elke dataset afzonderlijk verwerkt en vervolgens de resultaten samenvoegt, kun je de verwerking aanzienlijk versnellen, vooral op multiprocessorsystemen.
Gebruik van ForkJoinPool
Er zijn 2 klassen om taken in te implementeren, namelijk RecursiveTask en RecursiveAction. Beide vereisen dat de abstracte methode compute() wordt geïmplementeerd. In RecursiveTask geeft de methode compute() een waarde terug, terwijl in RecursiveAction de methode compute() void teruggeeft.
Main.java
12345678class ExampleTask extends RecursiveTask<String> { @Override protected String compute() { // code return null; } }
Wanneer we erven van een RecursiveTask, moeten we ervoor zorgen dat we het gegevenstype specificeren dat onze compute()-methode zal teruggeven met deze syntaxis: RecursiveTask<String>.
Main.java
1234567class ExampleAction extends RecursiveAction { @Override protected void compute() { // code } }
Hier is het tegenovergestelde het geval, we hoeven het type niet expliciet te specificeren in RecursiveAction, omdat onze methode niets zal teruggeven en alleen de taak zal uitvoeren.
Een taak starten
Overigens kunnen we een taak starten voor uitvoering zonder zelfs maar gebruik te maken van ForkJoinPool, door simpelweg de methoden fork() en join() te gebruiken.
Het is belangrijk op te merken dat de methode fork() de taak naar een willekeurige thread stuurt. De methode join() wordt gebruikt om het resultaat op te halen.
Main.java
12345public static void main(String[] args) { ExampleTask simpleClass = new ExampleTask(); simpleClass.fork(); System.out.println(simpleClass.join()); }
Belangrijkste methoden van ForkJoinPool
invoke(): Start een taak in de pool en wacht tot deze voltooid is. Geeft het resultaat van de taak terug;submit(): Dient een taak in bij de pool, maar blokkeert de huidige thread niet tijdens het wachten op voltooiing van de taak. Kan worden gebruikt om taken in te dienen en hunFuture-objecten op te halen;execute(): Voert een taak uit in de pool, maar geeft geen resultaat terug en blokkeert de huidige thread niet.
Hoe kunnen we een taak starten met behulp van ForkJoinPool, heel eenvoudig!
Main.java
12345public static void main(String[] args) { ExampleAction simpleClass = new ExampleAction(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); }
Maar wat is het verschil tussen uitvoeren met fork(), join() en via de ForkJoinPool klasse?
Het is heel eenvoudig! Bij gebruik van de eerste methode met behulp van de fork(), join() methoden, wordt de taak gestart in dezelfde thread waarin deze methoden zijn aangeroepen, waardoor deze thread wordt geblokkeerd, terwijl met behulp van de ForkJoinPool klasse een thread uit de pool wordt toegewezen en deze taak in die thread wordt uitgevoerd zonder de hoofdthread te blokkeren.
Laten we dit nader bekijken; stel dat we de volgende implementatie hebben:
Main.java
12345678class ExampleRecursiveTask extends RecursiveTask<String> { @Override protected String compute() { System.out.println("Thread: " + Thread.currentThread().getName()); return "Wow, it works!!!"; } }
En we willen deze code uitvoeren met behulp van fork() en join(). Laten we bekijken wat er op de console wordt afgedrukt en welke thread deze taak zal uitvoeren.
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); simpleClass.fork(); System.out.println(simpleClass.join()); } }
En we krijgen deze uitvoer op de console:
Thread: main
Wow, it works!!!
Laten we nu bekijken wat er gebeurt als we uitvoeren met ForkJoinPool:
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); } }
En we komen tot deze conclusie:
Thread: ForkJoinPool-1-worker-1
Wow, it works!!!
En zoals te zien is het verschil dat bij gebruik van de eerste methode de taak wordt uitgevoerd in dezelfde thread die deze taak heeft aangeroepen (Main thread). Maar als we de tweede methode gebruiken, wordt de thread uit de ForkJoinPool threadpool gehaald en wordt de hoofdthread die deze logica heeft aangeroepen niet geblokkeerd en gaat verder!
Hoe Fork/Join in Code te Implementeren
De eenvoudigste manier om dit uit te leggen is via een video, in plaats van je 50-80 regels code te geven en deze punt voor punt toe te lichten.
ForkJoinPool is effectief voor taken die eenvoudig kunnen worden opgesplitst in kleinere subtaken. Als de taken echter te klein zijn, levert het gebruik van ForkJoinPool mogelijk geen significante prestatieverbetering op.
Bedankt voor je feedback!