From 9cdc41268e75a577f2651627ab846708f7f8e458 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 16 Oct 2024 18:58:26 +0300 Subject: [PATCH] lab6 --- .../java/ru/lionarius/IntegralCalculator.java | 58 ++++++------- src/main/java/ru/lionarius/LazyStorage.java | 83 +++++++++++++++++++ src/main/java/ru/lionarius/Main.java | 26 +++--- 3 files changed, 120 insertions(+), 47 deletions(-) create mode 100644 src/main/java/ru/lionarius/LazyStorage.java diff --git a/src/main/java/ru/lionarius/IntegralCalculator.java b/src/main/java/ru/lionarius/IntegralCalculator.java index 8cfdd02..108b9d2 100644 --- a/src/main/java/ru/lionarius/IntegralCalculator.java +++ b/src/main/java/ru/lionarius/IntegralCalculator.java @@ -1,12 +1,7 @@ package ru.lionarius; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -26,7 +21,7 @@ public class IntegralCalculator { * The callback is called at least twice: once at the beginning, and once at the end of computation. * Takes the current step and the total number of steps. */ - private final BiConsumer progressCallback; + private final Consumer progressCallback; /** * Constructs an {@link IntegralCalculator} with the specified accuracy and an optional progress callback. @@ -36,7 +31,7 @@ public class IntegralCalculator { * @param progressCallback A callback function to track progress. Can be null. * @throws IllegalArgumentException if the accuracy is less than or equal to zero. */ - public IntegralCalculator(double accuracy, final BiConsumer progressCallback) { + public IntegralCalculator(double accuracy, final Consumer progressCallback) { if (accuracy <= 0.0) throw new IllegalArgumentException("accuracy must be a positive number"); @@ -73,20 +68,19 @@ public class IntegralCalculator { * @return The estimated value of the definite integral. * @throws NullPointerException if the function is null. */ - public double calculate(final Function function, double lower, double upper, ExecutorService executor, int parallelism) throws ExecutionException, InterruptedException { + public double calculate( + final Function function, + double lower, + double upper, + int parallelism + ) throws InterruptedException { if (function == null) throw new NullPointerException("function cannot be null"); - if (executor == null) - throw new NullPointerException("executor cannot be null"); - if (parallelism <= 0) throw new IllegalArgumentException("parallelism must be a positive number"); if (lower == upper) { - this.callProgressCallback(0, 1); - this.callProgressCallback(1, 1); - return 0.0; } @@ -105,35 +99,35 @@ public class IntegralCalculator { var n = (long) Math.ceil((upperBound - lowerBound) / this.accuracy); var h = (upperBound - lowerBound) / n; - this.callProgressCallback(0, n); - - var sum = (function.apply(lowerBound) + function.apply(upperBound)) / 2; - final var futures = new ArrayList>(); + var id = LazyStorage.getInstance().startCalculation(n); + LazyStorage.getInstance().setValue(id, (function.apply(lowerBound) + function.apply(upperBound)) / 2); + final var threads = new ArrayList(); for (var i = 0; i < parallelism; i++) { final var order = i; - futures.add(executor.submit(() -> { - var partitionSum = 0.0; + var thread = new Thread(() -> { for (var j = order; j < n; j += parallelism) { - partitionSum += function.apply(lowerBound + h * j); + LazyStorage.getInstance().addProgress(id, 1); + LazyStorage.getInstance().addToValue(id, function.apply(lowerBound + h * j)); - this.callProgressCallback(j, n); + if (j % (n / 15) == 0) + this.callProgressCallback(id); } - - return partitionSum; - })); + }); + thread.start(); + threads.add(thread); } - for (var future : futures) { - sum += future.get(); + for (var thread : threads) { + thread.join(); } + var sum = LazyStorage.getInstance().stopCalculation(id); + sum *= h; if (invert) sum = -sum; - this.callProgressCallback(n, n); - return sum; } @@ -143,8 +137,8 @@ public class IntegralCalculator { * @param current The current step in the integration process. * @param total The total number of steps in the integration process. */ - private void callProgressCallback(long current, long total) { + private void callProgressCallback(long id) { if (this.progressCallback != null) - this.progressCallback.accept(current, total); + this.progressCallback.accept(id); } } diff --git a/src/main/java/ru/lionarius/LazyStorage.java b/src/main/java/ru/lionarius/LazyStorage.java new file mode 100644 index 0000000..2c8c99c --- /dev/null +++ b/src/main/java/ru/lionarius/LazyStorage.java @@ -0,0 +1,83 @@ +package ru.lionarius; + +import java.util.HashMap; + +public class LazyStorage { + + private static volatile LazyStorage INSTANCE; + + private final HashMap calculations = new HashMap<>(); + private long currentId = 0; + + private LazyStorage() { + System.out.println("LazyStorage initialized"); + } + + public static LazyStorage getInstance() { + var instance = INSTANCE; + if (instance == null) { + synchronized (LazyStorage.class) { + instance = INSTANCE; + if (instance == null) { + INSTANCE = instance = new LazyStorage(); + } + } + } + return instance; + } + + public synchronized long startCalculation(long total) { + var calculation = new Calculation(); + calculation.total = total; + calculation.done = 0; + calculation.value = 0; + calculations.put(currentId, calculation); + + return this.currentId++; + } + + public synchronized void addProgress(long id, long progress) { + var calculation = calculations.get(id); + if (calculation != null) { + calculation.done += progress; + } + } + + public synchronized void setValue(long id, double value) { + var calculation = calculations.get(id); + if (calculation != null) { + calculation.value = value; + } + } + + public synchronized void addToValue(long id, double value) { + var calculation = calculations.get(id); + if (calculation != null) { + calculation.value += value; + } + } + + public synchronized double getProgress(long id) { + var calculation = calculations.get(id); + if (calculation == null) { + return 0; + } + + return (double) calculation.done / calculation.total; + } + + public synchronized double stopCalculation(long id) { + var calculation = calculations.remove(id); + if (calculation == null) { + return 0; + } + + return calculation.value; + } + + private static class Calculation { + public double value; + public long done; + public long total; + } +} diff --git a/src/main/java/ru/lionarius/Main.java b/src/main/java/ru/lionarius/Main.java index 70f0248..353c392 100644 --- a/src/main/java/ru/lionarius/Main.java +++ b/src/main/java/ru/lionarius/Main.java @@ -1,7 +1,5 @@ package ru.lionarius; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; import java.util.function.Function; public class Main { @@ -9,25 +7,25 @@ public class Main { Function function = x -> Math.sin(x) * x; var lowerBound = 0.0; var upperBound = 1.0; - double[] accuracies = {0.0001, 0.00001, 0.0000001, 0.000000001, 0.000000001}; - - var executor = Executors.newCachedThreadPool(); + double[] accuracies = {0.0001, 0.00001, 0.0000001, 0.00000001}; + for (final var accuracy : accuracies) { + var n = (long) (1 / accuracy); var calculator = new IntegralCalculator( - accuracy + accuracy, + (id) -> { + System.out.printf("[%s] Progress: %.2f%%%n", Thread.currentThread().getName(), 100 * LazyStorage.getInstance().getProgress(id)); + } ); var startTime = System.nanoTime(); - + double value = 0; try { - value = calculator.calculate(function, lowerBound, upperBound, executor, 1); - } catch (ExecutionException e) { - System.err.println("Error calculating integral: " + e.getMessage()); - } - catch (InterruptedException e) { + value = calculator.calculate(function, lowerBound, upperBound, 4); + } catch (InterruptedException e) { System.err.println("Thread interrupted: " + e.getMessage()); - executor.shutdown(); + return; } var totalTime = System.nanoTime() - startTime; @@ -39,7 +37,5 @@ public class Main { totalTime / 1_000_000.0 ); } - - executor.shutdown(); } }