From 1448d2184d11a1755c6e734ef808195ea5169243 Mon Sep 17 00:00:00 2001 From: mohammadreza Date: Mon, 8 Jun 2026 00:35:19 +0330 Subject: [PATCH 1/6] Added Report.md for the theoretical questions --- src/Report.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/Report.md diff --git a/src/Report.md b/src/Report.md new file mode 100644 index 0000000..e515634 --- /dev/null +++ b/src/Report.md @@ -0,0 +1,148 @@ +## Theoretical Questions πŸ“ + +### 1. `start()` vs `run()` + +```java +public class StartVsRun { + static class MyRunnable implements Runnable { + public void run() { + System.out.println("Running in: " + Thread.currentThread().getName()); + } + } + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(new MyRunnable(), "Thread-1"); + System.out.println("Calling run()"); + t1.run(); + Thread.sleep(100); + + Thread t2 = new Thread(new MyRunnable(), "Thread-2"); + System.out.println("Calling start()"); + t2.start(); + } +} +``` + +--- + +❓ What output do you get from the program? Why? + +βœ… Answer: + + +The program first prints: + +``` +Calling run() +Running in: main +``` +then it waits for 100ms (`Thread.sleep(100);`)
+then it prints: + +``` +Calling start() +Running in: Thread-2 +``` + +When t1.run() is called, it does not create a new thread. It just executes the run() method like a normal method inside the main thread. That is why the thread name is main. + +When t2.start() is called, Java creates a new separate thread, and then that new thread executes the run() method. That is why the thread name is Thread-2. + + +❓ What’s the difference in behavior between calling `start()` and `run()`? + +βœ… Answer: + +Calling run() directly only runs the code in the current thread, like a normal method call. + +Calling start() creates a new thread and then runs the run() method inside that new thread. So start() enables true multithreading, but run() does not. + +--- + +### 2. Daemon Threads + +```java +public class DaemonExample { + static class DaemonRunnable implements Runnable { + public void run() { + for(int i = 0; i < 20; i++) { + System.out.println("Daemon thread running..."); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + //[Handling Exception...] + } + } + } + } + public static void main(String[] args) { + Thread thread = new Thread(new DaemonRunnable()); + thread.setDaemon(true); + thread.start(); + System.out.println("Main thread ends."); + } +} +``` + +❓ What output do you get from the program? Why? + +βœ… Answer: + +The output will usually be: + +Main thread ends. + +The daemon thread may print "Daemon thread running..." zero or a few times, but it is not guaranteed to finish. This happens because daemon threads do not keep the JVM alive. When the main thread ends and there are no user threads left, the JVM can terminate immediately. + + +❓ What happens if you remove `thread.setDaemon(true)`? + +βœ… Answer: + +If thread.setDaemon(true) is removed, the thread becomes a normal user thread. + +In that case, the JVM will wait for it to finish. So the program will keep running until the loop finishes, and "Daemon thread running..." will be printed 20 times. + +❓ What are some real-life use cases of daemon threads? + +βœ… Answer: + +Daemon threads are useful for background tasks that should not prevent the program from exiting. + +Some examples are garbage collection, background monitoring, auto-saving, logging services, cache cleanup, and background resource management. + +--- + +### 3. A shorter way to create threads + +```java +public class ThreadDemo { + public static void main(String[] args) { + Thread thread = new Thread(() -> { + System.out.println("Thread is running using a ...!"); + }); + + thread.start(); + } +} +``` + +❓ What output do you get from the program? + +βœ… Answer: + +The output is: +Thread is running using a ...! + +❓ What is the `() -> { ... }` syntax called? + +βœ… Answer: + +The `() -> { ... }` syntax is called a lambda expression. + +❓ How is this code different from creating a class that extends `Thread` or implements `Runnable`? + +βœ… Answer: + +This code uses a lambda expression to provide the implementation of the Runnable interface directly. + +It is shorter and cleaner than creating a separate class that extends Thread or implements Runnable. It is useful when the thread task is simple and only needed once. From 015734784fa7e86ac71057ec95373ee3ee185881 Mon Sep 17 00:00:00 2001 From: mohammadreza Date: Mon, 8 Jun 2026 00:36:38 +0330 Subject: [PATCH 2/6] implement DownloadWorker.java --- src/main/java/DownloadWorker.java | 60 ++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java index 546de2d..f596a9e 100644 --- a/src/main/java/DownloadWorker.java +++ b/src/main/java/DownloadWorker.java @@ -1,4 +1,5 @@ import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * Simulates downloading a single chunk of a file. @@ -11,33 +12,66 @@ public class DownloadWorker implements Runnable { private final ChunkStatus chunkStatus; private final DownloadConfig config; - private final Random random; public DownloadWorker(ChunkStatus chunkStatus, DownloadConfig config) { this.chunkStatus = chunkStatus; this.config = config; - this.random = new Random(); } @Override public void run() { - // TODO: Record the chunk start time in chunkStatus. + long start = System.currentTimeMillis(); + chunkStatus.setStartTimeMs(start); + double downloaded = 0.0; - // TODO: Print a message that this chunk has started downloading. + System.out.println( + "Chunk (id: " + chunkStatus.getChunkId() + ") has started downloading." + ); while (downloaded < chunkStatus.getChunkSizeMB()) { - // TODO: Generate a random sleep delay between min and max delay. - // TODO: Sleep for that delay. - // TODO: Generate a random download amount for this step. - // TODO: Increase downloaded, but do not go beyond chunk size. - // TODO: Save the updated downloaded value into chunkStatus. - // TODO: Optionally print step-by-step progress. + + int randomSleepDelay = ThreadLocalRandom.current().nextInt( + config.getMinStepDelayMs(), + config.getMaxStepDelayMs() + 1 + ); + + try { + Thread.sleep(randomSleepDelay); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + double randomDownloadAmount = ThreadLocalRandom.current().nextDouble( + config.getMinStepDownloadMB(), + config.getMaxStepDownloadMB() + ); + + downloaded += randomDownloadAmount; + + if (downloaded > chunkStatus.getChunkSizeMB()) { + downloaded = chunkStatus.getChunkSizeMB(); + } + + chunkStatus.setDownloadedMB(downloaded); + + System.out.println( + "Chunk (id: " + chunkStatus.getChunkId() + ") progress: " + + downloaded + " / " + + chunkStatus.getChunkSizeMB() + " MB" + ); } - // TODO: Mark the chunk as completed. - // TODO: Record the chunk end time in chunkStatus. - // TODO: Print a message that this chunk has finished downloading. + chunkStatus.setCompleted(true); + + long end = System.currentTimeMillis(); + chunkStatus.setEndTimeMs(end); + + System.out.println( + "Chunk (id: " + chunkStatus.getChunkId() + ") has finished downloading. Took: " + + chunkStatus.getDownloadDurationMs() + " ms" + ); } } From 09ac99ee80145bd0cd2dc0f1b0544f44aceec206 Mon Sep 17 00:00:00 2001 From: mohammadreza Date: Mon, 8 Jun 2026 00:37:50 +0330 Subject: [PATCH 3/6] implement ProgressMonitor.java --- src/main/java/ProgressMonitor.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/ProgressMonitor.java b/src/main/java/ProgressMonitor.java index 475c0e0..befeb1d 100644 --- a/src/main/java/ProgressMonitor.java +++ b/src/main/java/ProgressMonitor.java @@ -58,6 +58,11 @@ public class ProgressMonitor implements Runnable { // TODO: // If all chunks are completed, print a final message and exit the loop + if (completedChunks == chunks.size()) { + System.out.println("progress monitor is ended..."); + break; + } + try { Thread.sleep(monitorDelayMs); } catch (InterruptedException e) { From 5fdcd9349cfd33e1485bf439ea860550baddd95a Mon Sep 17 00:00:00 2001 From: mohammadreza Date: Mon, 8 Jun 2026 00:39:47 +0330 Subject: [PATCH 4/6] implement Main.java --- src/main/java/Main.java | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 82bd239..81040db 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -37,12 +37,38 @@ public class Main { // TODO: // Students may print helpful debug information here, // for example which chunk is assigned to which worker thread. + System.out.println( + "new thread " + workerThread.getName() + " created for chunk " + chunk.getChunkId() + ); } // 4. Create and start monitor thread ProgressMonitor monitor = new ProgressMonitor(config, chunks); Thread monitorThread = new Thread(monitor, "Progress-Monitor"); + monitorThread.start(); + + for (Thread thread : workerThreads) { + + thread.start(); + } + + try { + for (Thread thread : workerThreads) { + thread.join(); + } + } catch (InterruptedException e) { + System.out.println("Download manager was interrupted. Stopping all workers..."); + monitorThread.interrupt(); + + for (Thread worker : workerThreads) { + worker.interrupt(); + } + + Thread.currentThread().interrupt(); + return; + } + // TODO: // Start the monitor thread before starting the workers // so that progress can be displayed while downloading happens. From a7fbc21be9caac3621731b1a99cd2c30ac2eb261 Mon Sep 17 00:00:00 2001 From: mohammadreza Date: Mon, 8 Jun 2026 11:46:12 +0330 Subject: [PATCH 5/6] debug DownloadWorker.java --- src/main/java/DownloadWorker.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java index f596a9e..c56a5f4 100644 --- a/src/main/java/DownloadWorker.java +++ b/src/main/java/DownloadWorker.java @@ -20,13 +20,15 @@ public class DownloadWorker implements Runnable { @Override public void run() { - long start = System.currentTimeMillis(); - chunkStatus.setStartTimeMs(start); + + chunkStatus.setStartTimeMs(System.currentTimeMillis()); double downloaded = 0.0; System.out.println( - "Chunk (id: " + chunkStatus.getChunkId() + ") has started downloading." + "[Worker-" + chunkStatus.getChunkId() + + "] Started downloading chunk of size: " + + String.format("%.2f", chunkStatus.getChunkSizeMB()) + " MB" ); while (downloaded < chunkStatus.getChunkSizeMB()) { @@ -38,7 +40,9 @@ public class DownloadWorker implements Runnable { try { Thread.sleep(randomSleepDelay); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); return; } From 3afed369abe1b479efc0dbcbc881df10d0054fd1 Mon Sep 17 00:00:00 2001 From: mohammadreza Date: Mon, 8 Jun 2026 11:54:00 +0330 Subject: [PATCH 6/6] renamed to Report.md --- src/Report.md => Report.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Report.md => Report.md (100%) diff --git a/src/Report.md b/Report.md similarity index 100% rename from src/Report.md rename to Report.md