[BAEL-6486] - Returning a Value After Finishing Thread's Job in Java (#14101)

* feat: threads with return value

* pmd violation
This commit is contained in:
lucaCambi77 2023-06-06 03:52:46 +02:00 committed by GitHub
parent 9ff3b1dd9b
commit f265b51841
8 changed files with 252 additions and 0 deletions

View File

@ -0,0 +1,29 @@
package com.baeldung.concurrent.threadreturnvalue.task;
import java.math.BigInteger;
public class FactorialCalculator {
public static BigInteger factorial(BigInteger end) {
BigInteger start = BigInteger.ONE;
BigInteger res = BigInteger.ONE;
for (int i = start.add(BigInteger.ONE)
.intValue(); i <= end.intValue(); i++) {
res = res.multiply(BigInteger.valueOf(i));
}
return res;
}
public static BigInteger factorial(BigInteger start, BigInteger end) {
BigInteger res = start;
for (int i = start.add(BigInteger.ONE)
.intValue(); i <= end.intValue(); i++) {
res = res.multiply(BigInteger.valueOf(i));
}
return res;
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.concurrent.threadreturnvalue.task.callable;
import java.math.BigInteger;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableExecutor {
public BigInteger execute(List<CallableFactorialTask> tasks) {
BigInteger result = BigInteger.ZERO;
ExecutorService cachedPool = Executors.newCachedThreadPool();
List<Future<BigInteger>> futures;
try {
futures = cachedPool.invokeAll(tasks);
} catch (InterruptedException e) {
// exception handling example
throw new RuntimeException(e);
}
for (Future<BigInteger> future : futures) {
try {
result = result.add(future.get());
} catch (InterruptedException | ExecutionException e) {
// exception handling example
throw new RuntimeException(e);
}
}
return result;
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.concurrent.threadreturnvalue.task.callable;
import static com.baeldung.concurrent.threadreturnvalue.task.FactorialCalculator.factorial;
import java.math.BigInteger;
import java.util.concurrent.Callable;
public class CallableFactorialTask implements Callable<BigInteger> {
private final Integer value;
public CallableFactorialTask(int value) {
this.value = value;
}
@Override
public BigInteger call() {
return factorial(BigInteger.valueOf(value));
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.concurrent.threadreturnvalue.task.fork;
import java.math.BigInteger;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
public class ForkExecutor {
private final ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
public BigInteger execute(ForkFactorialTask forkFactorial) {
return forkJoinPool.invoke(forkFactorial);
}
public BigInteger execute(List<Callable<BigInteger>> forkFactorials) {
List<Future<BigInteger>> futures = forkJoinPool.invokeAll(forkFactorials);
BigInteger result = BigInteger.ZERO;
for (Future<BigInteger> future : futures) {
try {
result = result.add(future.get());
} catch (InterruptedException | ExecutionException e) {
// exception handling example
throw new RuntimeException(e);
}
}
return result;
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.concurrent.threadreturnvalue.task.fork;
import static com.baeldung.concurrent.threadreturnvalue.task.FactorialCalculator.factorial;
import java.math.BigInteger;
import java.util.concurrent.RecursiveTask;
public class ForkFactorialTask extends RecursiveTask<BigInteger> {
private final int start;
private final int end;
private final int threshold;
public ForkFactorialTask(int end, int threshold) {
this.start = 1;
this.end = end;
this.threshold = threshold;
}
public ForkFactorialTask(int start, int end, int threshold) {
this.start = start;
this.end = end;
this.threshold = threshold;
}
@Override
protected BigInteger compute() {
BigInteger sum = BigInteger.ONE;
if (end - start > threshold) {
int middle = (end + start) / 2;
return sum.multiply(new ForkFactorialTask(start, middle, threshold).fork()
.join()
.multiply(new ForkFactorialTask(middle + 1, end, threshold).fork()
.join()));
}
return sum.multiply(factorial(BigInteger.valueOf(start), BigInteger.valueOf(end)));
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.concurrent.threadreturnvalue.callable;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.math.BigInteger;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import com.baeldung.concurrent.threadreturnvalue.task.callable.CallableExecutor;
import com.baeldung.concurrent.threadreturnvalue.task.callable.CallableFactorialTask;
public class CallableUnitTest {
private final CallableExecutor callableExecutor = new CallableExecutor();
@Test
void givenCallableExecutor_whenExecuteFactorial_thenResultOk() {
BigInteger result = callableExecutor.execute(Arrays.asList(new CallableFactorialTask(5), new CallableFactorialTask(3)));
assertEquals(BigInteger.valueOf(126), result);
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.concurrent.threadreturnvalue.completableFuture;
import static com.baeldung.concurrent.threadreturnvalue.task.FactorialCalculator.factorial;
import static java.util.concurrent.CompletableFuture.allOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.math.BigInteger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;
public class CompletableFutureUnitTest {
@Test
void givenCompletableFuture_whenSupplyAsyncFactorial_thenResultOk() throws ExecutionException, InterruptedException {
CompletableFuture<BigInteger> completableFuture = CompletableFuture.supplyAsync(() -> factorial(BigInteger.valueOf(10)));
assertEquals(BigInteger.valueOf(3628800), completableFuture.get());
}
@Test
void givenCompletableFuture_whenComposeTasks_thenResultOk() throws ExecutionException, InterruptedException {
CompletableFuture<BigInteger> completableFuture = CompletableFuture.supplyAsync(() -> factorial(BigInteger.valueOf(3)))
.thenCompose(inputFromFirstTask -> CompletableFuture.supplyAsync(() -> factorial(inputFromFirstTask)));
assertEquals(BigInteger.valueOf(720), completableFuture.get());
}
@Test
void givenCompletableFuture_whenAllOfTasks_thenResultOk() {
CompletableFuture<BigInteger> asyncTask1 = CompletableFuture.supplyAsync(() -> BigInteger.valueOf(5));
CompletableFuture<String> asyncTask2 = CompletableFuture.supplyAsync(() -> "3");
BigInteger result = allOf(asyncTask1, asyncTask2).thenApplyAsync(fn -> factorial(asyncTask1.join()).add(factorial(new BigInteger(asyncTask2.join()))), Executors.newFixedThreadPool(1))
.join();
assertEquals(BigInteger.valueOf(126), result);
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.concurrent.threadreturnvalue.fork;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.math.BigInteger;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import com.baeldung.concurrent.threadreturnvalue.task.callable.CallableFactorialTask;
import com.baeldung.concurrent.threadreturnvalue.task.fork.ForkExecutor;
import com.baeldung.concurrent.threadreturnvalue.task.fork.ForkFactorialTask;
public class ForkUnitTest {
private final ForkExecutor forkExecutor = new ForkExecutor();
@Test
void givenForkExecutor_whenExecuteRecursiveTask_thenResultOk() {
assertEquals(BigInteger.valueOf(3628800), forkExecutor.execute(new ForkFactorialTask(10, 5)));
}
@Test
void givenForkExecutor_whenExecuteCallable_thenResultOk() {
assertEquals(BigInteger.valueOf(126), forkExecutor.execute(Arrays.asList(new CallableFactorialTask(5), new CallableFactorialTask(3))));
}
}