From 40c099176d7c6217c5dad12619a481012ecabd15 Mon Sep 17 00:00:00 2001 From: AryanGh-imp Date: Fri, 30 May 2025 17:57:57 +0330 Subject: [PATCH 1/4] Theoretical questions have been completed --- .idea/misc.xml | 2 +- Report.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 Report.md diff --git a/.idea/misc.xml b/.idea/misc.xml index 5cd9a10..12591c7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/Report.md b/Report.md new file mode 100644 index 0000000..4209df4 --- /dev/null +++ b/Report.md @@ -0,0 +1,79 @@ +### `Atomic Variables` + +```java +import java.util.concurrent.atomic.AtomicInteger; +public class AtomicDemo { + private static AtomicInteger atomicCounter = new AtomicInteger(0); + private static int normalCounter = 0; + public static void main(String[] args) throws InterruptedException { + Runnable task = () -> { + for (int i = 0; i < 1_000_000; i++) { + atomicCounter.incrementAndGet(); + normalCounter++; + } + }; + + Thread t1 = new Thread(task); + Thread t2 = new Thread(task); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + System.out.println("Atomic Counter: " + atomicCounter); + System.out.println("Normal Counter: " + normalCounter); + } +} + +``` + +**Questions:** + +- What output do you get from the program? Why? + +- What is the purpose of AtomicInteger in this code? + +- What thread-safety guarantees does atomicCounter.incrementAndGet() provide? + +- In which situations would using a lock be a better choice than an atomic variable? + +- Besides AtomicInteger, what other data types are available in the java.util.concurrent.atomic package? + +--- + +### Answers : + +#### Q1 : + +- Atomic Counter: 2000000 +- Normal Counter: Less than 2000000 + +##### Why: + +- `atomicCounter` uses `AtomicInteger`, which ensures atomic increments, resulting in exactly 2,000,000 (1M increments per thread). + +- `normalCounter` is a regular `int`, and `normalCounter++` is not atomic, leading to race conditions where some increments are lost due to concurrent modifications. + +#### Q2 : + +`AtomicInteger` provides thread-safe, atomic operations to safely increment `atomicCounter` without locks, preventing race conditions in a multithreaded environment. + +#### Q3 : + +`incrementAndGet()` is atomic, ensuring that the read, increment, and write operations are performed as a single, indivisible unit. + +It guarantees visibility (changes are immediately visible to all threads) and prevents race conditions. + +#### Q4 : + +- When operations involve multiple variables or complex logic that require mutual exclusion (e.g., updating two counters consistently). +- When fairness or explicit control over locking (e.g., ReentrantLock) is needed. + +#### Q5 : + +##### Other Data Types: + +- `AtomicLong`: For atomic operations on `long` values. +- `AtomicBoolean`: For atomic operations on `boolean` values. +- `AtomicReference`: For atomic operations on object references. +- `AtomicIntegerArray`, `AtomicLongArray`, `AtomicReferenceArray`: For arrays of atomic integers, longs, or references. \ No newline at end of file From caf55ed9846071a32b50074f062cc6fc9210dd4c Mon Sep 17 00:00:00 2001 From: AryanGh-imp Date: Sat, 31 May 2025 03:46:56 +0330 Subject: [PATCH 2/4] MonteCarloPi.java has been completed --- src/main/java/MonteCarloPI/MonteCarloPi.java | 76 +++++++++++++++----- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/src/main/java/MonteCarloPI/MonteCarloPi.java b/src/main/java/MonteCarloPI/MonteCarloPi.java index 861fe73..265e902 100644 --- a/src/main/java/MonteCarloPI/MonteCarloPi.java +++ b/src/main/java/MonteCarloPI/MonteCarloPi.java @@ -1,8 +1,10 @@ package MonteCarloPI; -import java.util.concurrent.ExecutionException; +import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; public class MonteCarloPi { @@ -25,31 +27,73 @@ public static void main(String[] args) throws InterruptedException, ExecutionExc endTime = System.nanoTime(); System.out.println("Monte Carlo Pi Approximation (Multi-threaded): " + piWithThreads); System.out.println("Time taken (Multi-threaded): " + (endTime - startTime) / 1_000_000 + " ms"); - - // TODO: After completing the implementation, reflect on the questions in the description of this task in the README file - // and include your answers in your report file. } // Monte Carlo Pi Approximation without threads public static double estimatePiWithoutThreads(long numPoints) { - // TODO: Implement this method to calculate Pi using a single thread - return 0; + Random random = new Random(); + long pointsInsideCircle = 0; + + for (long i = 0; i < numPoints; i++) { + double x = random.nextDouble() * 2 - 1; // x in [-1, 1] + double y = random.nextDouble() * 2 - 1; // y in [-1, 1] + if (x * x + y * y <= 1) { // Inside circle + pointsInsideCircle++; + } + } + + return 4.0 * pointsInsideCircle / numPoints; } // Monte Carlo Pi Approximation with threads - public static double estimatePiWithThreads(long numPoints, int numThreads) throws InterruptedException, ExecutionException - { - // TODO: Implement this method to calculate Pi using multiple threads + public static double estimatePiWithThreads(long numPoints, int numThreads) throws InterruptedException { + AtomicLong pointsInsideCircle = new AtomicLong(0); + Thread[] threads = new Thread[numThreads]; + long pointsPerThread = numPoints / numThreads; + long remainingPoints = numPoints % numThreads; + + // Distribute points among threads using try-with-resources + try (ExecutorService executor = Executors.newFixedThreadPool(numThreads)) { + for (int i = 0; i < numThreads; i++) { + long pointsForThisThread = pointsPerThread + (i == 0 ? remainingPoints : 0); + threads[i] = new Thread(new PiTask(pointsForThisThread, pointsInsideCircle)); + executor.execute(threads[i]); // Use executor to manage threads + } + + // Wait for all threads to complete + for (Thread thread : threads) { + thread.join(); + } + } // ExecutorService automatically shuts down here + + return 4.0 * pointsInsideCircle.get() / numPoints; + } + + // Task for each thread + private static class PiTask implements Runnable { + private final long numPoints; + private final AtomicLong pointsInsideCircle; + + public PiTask(long numPoints, AtomicLong pointsInsideCircle) { + this.numPoints = numPoints; + this.pointsInsideCircle = pointsInsideCircle; + } - ExecutorService executor = Executors.newFixedThreadPool(numThreads); + @Override + public void run() { + Random random = new Random(); + long localCount = 0; - // HINT: You may need to create a variable to *safely* keep track of points that fall inside the circle - // HINT: Each thread should generate and process a subset of the total points + for (long i = 0; i < numPoints; i++) { + double x = random.nextDouble() * 2 - 1; + double y = random.nextDouble() * 2 - 1; + if (x * x + y * y <= 1) { + localCount++; + } + } - // TODO: After submitting all tasks, shut down the executor to prevent new tasks - // TODO: wait for the executor to be fully terminated - // TODO: Calculate and return the final estimation of Pi - return 0; + pointsInsideCircle.addAndGet(localCount); + } } } \ No newline at end of file From f61876d141f7b6b2e6c30c568e27cef07b479950 Mon Sep 17 00:00:00 2001 From: AryanGh-imp Date: Sat, 31 May 2025 03:49:37 +0330 Subject: [PATCH 3/4] Report.md has been updated (Explanations have been added for questions about MonteCarloPi.java) --- Report.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/Report.md b/Report.md index 4209df4..0c98dca 100644 --- a/Report.md +++ b/Report.md @@ -1,4 +1,4 @@ -### `Atomic Variables` +# Atomic Variables ```java import java.util.concurrent.atomic.AtomicInteger; @@ -27,7 +27,7 @@ public class AtomicDemo { ``` -**Questions:** +## **Questions:** - What output do you get from the program? Why? @@ -41,39 +41,86 @@ public class AtomicDemo { --- -### Answers : +## **Answers** : -#### Q1 : +### Q1 : - Atomic Counter: 2000000 - Normal Counter: Less than 2000000 -##### Why: +#### Why: - `atomicCounter` uses `AtomicInteger`, which ensures atomic increments, resulting in exactly 2,000,000 (1M increments per thread). - `normalCounter` is a regular `int`, and `normalCounter++` is not atomic, leading to race conditions where some increments are lost due to concurrent modifications. -#### Q2 : +### Q2 : `AtomicInteger` provides thread-safe, atomic operations to safely increment `atomicCounter` without locks, preventing race conditions in a multithreaded environment. -#### Q3 : +### Q3 : `incrementAndGet()` is atomic, ensuring that the read, increment, and write operations are performed as a single, indivisible unit. It guarantees visibility (changes are immediately visible to all threads) and prevents race conditions. -#### Q4 : +### Q4 : - When operations involve multiple variables or complex logic that require mutual exclusion (e.g., updating two counters consistently). - When fairness or explicit control over locking (e.g., ReentrantLock) is needed. -#### Q5 : +### Q5 : -##### Other Data Types: +#### Other Data Types: - `AtomicLong`: For atomic operations on `long` values. - `AtomicBoolean`: For atomic operations on `boolean` values. - `AtomicReference`: For atomic operations on object references. -- `AtomicIntegerArray`, `AtomicLongArray`, `AtomicReferenceArray`: For arrays of atomic integers, longs, or references. \ No newline at end of file +- `AtomicIntegerArray`, `AtomicLongArray`, `AtomicReferenceArray`: For arrays of atomic integers, longs, or references. + +--- + +# Monte Carlo π Estimation Report + +## Performance Comparison + +- **Single-Threaded Version:** + - Execution Time: ~1.4-2 seconds for 50,000,000 points. + - Estimated π: ~3.1416 (accuracy depends on point count). + +- **Multi-Threaded Version (4 threads):** + - Execution Time: ~0.1-0.3 second for 50,000,000 points. + - Estimated π: ~3.1416 (same accuracy as single-threaded). + +one of the outputs : +``` +Single threaded calculation started: +Monte Carlo Pi Approximation (single thread): 3.14150792 +Time taken (single threads): 1553 ms +Multi threaded calculation started: (your device has 32 logical threads) +Monte Carlo Pi Approximation (Multi-threaded): 3.14165904 +Time taken (Multi-threaded): 161 ms +``` +## Questions + +### Was the multi-threaded implementation always faster than the single-threaded one? + +No, the multi-threaded implementation is not always faster. + +**Why not?** +- Small point counts (e.g., 10,000) incur thread pool setup overhead that outweighs processing time. +- Excessive threads beyond CPU cores (e.g., 16 threads on 4 cores) cause context switching overhead. +- Single-core systems lack parallelism, making multi-threading slower. +- Uneven point distribution (mitigated in this code) can lead to idle threads. + +### If not, what factors are the cause and what can you do to mitigate these issues? + +**Factors:** +- **Thread pool setup overhead:** Initializing `ExecutorService` is costly for small point counts. +- **Context switching:** Excessive threads beyond CPU cores increase switching overhead. +- **Hardware limitations:** Single-core systems lack parallelism. + +**Mitigations:** +- Use `ExecutorService` to reuse threads, reducing creation overhead. +- Set thread count to match CPU cores (`availableProcessors()`). +- Fall back to single-threaded version for small point counts (<1M). \ No newline at end of file From 42fc263214b3284c39dac6fd601194c95162e73f Mon Sep 17 00:00:00 2001 From: AryanGh-imp Date: Sat, 31 May 2025 13:39:09 +0330 Subject: [PATCH 4/4] Banking system has been completed --- src/main/java/Banking/BankAccount.java | 37 +++++++++++++++++++++----- src/main/java/Banking/BankingMain.java | 2 +- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/java/Banking/BankAccount.java b/src/main/java/Banking/BankAccount.java index 801bbfa..1844d73 100644 --- a/src/main/java/Banking/BankAccount.java +++ b/src/main/java/Banking/BankAccount.java @@ -17,8 +17,7 @@ public int getId(){ return id; } public int getBalance() { - // TODO: Consider locking (if needed) - return balance; + return balance; // No need for a lock, as access to the balance is safe in other methods } public Lock getLock() { @@ -26,16 +25,40 @@ public Lock getLock() { } public void deposit(int amount) { - // TODO: Safely add to balance. + lock.lock(); + try { + balance += amount; + } finally { + lock.unlock(); + } } public void withdraw(int amount) { - // TODO: Safely withdraw from balance. + lock.lock(); + try { + balance -= amount; + } finally { + lock.unlock(); + } } public void transfer(BankAccount target, int amount) { - // TODO: Safely make the changes - // HINT: Both accounts need to be locked, while the changes are being made - // HINT: Be cautious of potential deadlocks. + // Locking order by id to avoid deadlock + Lock firstLock = this.id < target.id ? this.lock : target.lock; + Lock secondLock = this.id < target.id ? target.lock : this.lock; + + firstLock.lock(); + try { + secondLock.lock(); + try { + this.balance -= amount; // Deduction from the first account + target.balance += amount; // Deposit to destination account + } finally { + secondLock.unlock(); + } + } finally { + firstLock.unlock(); + } } + } diff --git a/src/main/java/Banking/BankingMain.java b/src/main/java/Banking/BankingMain.java index 0e52f8f..095f09c 100644 --- a/src/main/java/Banking/BankingMain.java +++ b/src/main/java/Banking/BankingMain.java @@ -15,7 +15,7 @@ public List calculate() throws InterruptedException { Thread[] threads = new Thread[4]; for(int i = 1; i <= 4; i++){ String fileName = i + ".txt"; - threads[i - 1] = new Thread(new TransactionProcessor(accounts.get(i - 1), fileName, accounts)); + threads[i - 1] = new Thread(new TransactionProcessor(accounts.get(i - 1), fileName, accounts) , ("Acc-" + i)); } for(Thread thread : threads){