From 57079f70f15ea7e8bde4cb93cc1b4112f42232e2 Mon Sep 17 00:00:00 2001 From: Arshida_0 Date: Thu, 4 Jun 2026 19:52:17 +0430 Subject: [PATCH] HW 08 --- Report.md | 46 ++++++++++++++++++++++++++ src/main/java/DownloadWorker.java | 30 +++++++++++++++++ src/main/java/Main.java | 17 ++++++++++ src/main/java/ProgressMonitor.java | 4 +++ src/main/resources/download_config.txt | 4 +-- 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 Report.md diff --git a/Report.md b/Report.md new file mode 100644 index 0000000..9e4bd08 --- /dev/null +++ b/Report.md @@ -0,0 +1,46 @@ +## Answers to Theoretical Questions + +### 1. `start()` vs `run()` + +**Output:** +```text +Calling run() +Running in: main +Calling start() +Running in: Thread-2 +``` + +- When calling run method, no matter what thread it is called through, the program uses the thread it is called in. So here, the run method would be runed in the main thread. + +- On the other hand, the start method runs the run method in the thread in which it is created or overridden. In this case, it would be the second thread. + +- Hence, the key difference between the two methods run & start is where they run the runnable method given to the thread. + +--- + +### 2. Daemon Threads + +**Output:** +```text +Main thread ends. +Daemon thread running... +``` + +- By turning the thread into a daemon thread, the program only runs until the last user thread finishes its task; shortly after that, the program running ends ignoring the daemon threads and their left tasks. + +- If we remove `thread.setDaemon(true)` from the code, the thread would be considered a user thread. The program runs until the thread finishes its task. Here, it would print `Daemon thread running...` 20 times in total. + +- Two real-life use cases of daemon threads are garbage collectors and auto-save features in editors. + +--- + +### 3. A shorter way to create threads + +**Output:** +```text +Thread is running using a ...! +``` + +- the `() -> { ... }` syntax is called a lambda expression. + +- By using a lambda expression, there is no need for creating a whole class to run the task. It also decreases the number of lines we need to code. So it is recommended over using another class especially if the method we want to run is not complicated. \ No newline at end of file diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java index 546de2d..d3db5b0 100644 --- a/src/main/java/DownloadWorker.java +++ b/src/main/java/DownloadWorker.java @@ -22,22 +22,52 @@ public class DownloadWorker implements Runnable { @Override public void run() { // TODO: Record the chunk start time in chunkStatus. + chunkStatus.setStartTimeMs(System.currentTimeMillis()); + double downloaded = 0.0; // TODO: Print a message that this chunk has started downloading. + System.out.println("The chunk has started downloading."); while (downloaded < chunkStatus.getChunkSizeMB()) { // TODO: Generate a random sleep delay between min and max delay. + int max1 = config.getMaxStepDelayMs(); + int min1 = config.getMinStepDelayMs(); + int randomDelay = random.nextInt(max1 - min1 + 1) + min1; + // TODO: Sleep for that delay. + try { + Thread.sleep(randomDelay); + } catch (InterruptedException e) { + //... + } + // TODO: Generate a random download amount for this step. + double max2 = config.getMaxStepDownloadMB(); + double min2 = config.getMinStepDownloadMB(); + double randomDownloadedAmount = random.nextDouble(max2 - min2 + 1) + min2; + // TODO: Increase downloaded, but do not go beyond chunk size. + downloaded += randomDownloadedAmount; + // TODO: Save the updated downloaded value into chunkStatus. + chunkStatus.setDownloadedMB(downloaded); + // TODO: Optionally print step-by-step progress. + System.out.println(String.format("Chunk-%d: %.1f/%.1f MB", + chunkStatus.getChunkId(), + chunkStatus.getDownloadedMB(), + chunkStatus.getChunkSizeMB())); } // TODO: Mark the chunk as completed. + chunkStatus.setCompleted(true); + // TODO: Record the chunk end time in chunkStatus. + chunkStatus.setEndTimeMs(System.currentTimeMillis()); + // TODO: Print a message that this chunk has finished downloading. + System.out.println(String.format("Chunk-%d has finished downloading.", chunkStatus.getChunkId())); } } diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 82bd239..e77f3fa 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -37,6 +37,7 @@ public class Main { // TODO: // Students may print helpful debug information here, // for example which chunk is assigned to which worker thread. + System.out.println("Chunk " + chunk.getChunkId() + " is assigned to " + workerThread.getName()); } // 4. Create and start monitor thread @@ -49,11 +50,15 @@ public class Main { // // Example idea: // monitorThread.start(); + monitorThread.start(); // 5. Start worker threads // TODO: // Start each worker thread in workerThreads. // Use a loop and call start() on each thread. + for (Thread thread : workerThreads) { + thread.start(); + } // 6. Wait for workers to finish // TODO: @@ -64,6 +69,13 @@ public class Main { // for (Thread thread : workerThreads) { // thread.join(); // } + for (Thread thread : workerThreads) { + try { + thread.join(); + } catch (InterruptedException e) { + //... + } + } // TODO: // After all workers finish, the monitor thread may also need to stop. @@ -72,6 +84,11 @@ public class Main { // - add a stopping mechanism in ProgressMonitor later. // // If your monitor finishes automatically, you may join it here. + try { + monitorThread.join(); + } catch (InterruptedException e) { + //... + } // NOTE: // this final report may show 0 progress because no worker has actually run yet. diff --git a/src/main/java/ProgressMonitor.java b/src/main/java/ProgressMonitor.java index 475c0e0..b030326 100644 --- a/src/main/java/ProgressMonitor.java +++ b/src/main/java/ProgressMonitor.java @@ -57,6 +57,10 @@ 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("All chunks are completed."); + return; + } try { Thread.sleep(monitorDelayMs); diff --git a/src/main/resources/download_config.txt b/src/main/resources/download_config.txt index 6ddd6ca..8e31842 100644 --- a/src/main/resources/download_config.txt +++ b/src/main/resources/download_config.txt @@ -1,6 +1,6 @@ fileName=movie.mkv -totalSizeMB=120 -chunkCount=6 +totalSizeMB=170 +chunkCount=5 minStepDelayMs=80 maxStepDelayMs=200 minStepDownloadMB=2 -- 2.54.0