diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java
index 546de2d..8ad68f3 100644
--- a/src/main/java/DownloadWorker.java
+++ b/src/main/java/DownloadWorker.java
@@ -1,12 +1,5 @@
import java.util.Random;
-/**
- * Simulates downloading a single chunk of a file.
- *
- *
This class is intentionally provided as a skeleton for students.
- * The main multithreading and simulation logic should be completed
- * in the run() method.
- */
public class DownloadWorker implements Runnable {
private final ChunkStatus chunkStatus;
@@ -21,23 +14,34 @@ 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("[Worker-" + chunkStatus.getChunkId() + "] Started downloading chunk of size: " + String.format("%.2f", chunkStatus.getChunkSizeMB()) + " MB");
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.
+ try {
+ int delay = config.getMinStepDelayMs() + random.nextInt(config.getMaxStepDelayMs() - config.getMinStepDelayMs() + 1);
+ Thread.sleep(delay);
+
+ double stepDownload = config.getMinStepDownloadMB() + (random.nextDouble() * (config.getMaxStepDownloadMB() - config.getMinStepDownloadMB()));
+
+ downloaded += stepDownload;
+ if (downloaded > chunkStatus.getChunkSizeMB()) {
+ downloaded = chunkStatus.getChunkSizeMB();
+ }
+
+ chunkStatus.setDownloadedMB(downloaded);
+
+ } catch (InterruptedException e) {
+ System.err.println("Worker-" + chunkStatus.getChunkId() + " was interrupted.");
+ return;
+ }
}
- // 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);
+ chunkStatus.setEndTimeMs(System.currentTimeMillis());
-}
+ System.out.println("[Worker-" + chunkStatus.getChunkId() + "] Finished downloading.");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Main.java b/src/main/java/Main.java
index 82bd239..e943089 100644
--- a/src/main/java/Main.java
+++ b/src/main/java/Main.java
@@ -5,7 +5,6 @@ public class Main {
public static void main(String[] args) {
System.out.println("=== Simulated Download Manager ===");
- // 1. Read config
DownloadConfig config;
try {
config = ConfigReader.readConfig("download_config.txt");
@@ -19,65 +18,38 @@ public class Main {
System.out.println("Chunk count: " + config.getChunkCount());
System.out.println();
- // 2. Create chunks
List chunks = ChunkUtils.createChunks(
config.getTotalSizeMB(),
config.getChunkCount()
);
- // 3. Create worker threads
List workerThreads = new ArrayList<>();
for (ChunkStatus chunk : chunks) {
DownloadWorker worker = new DownloadWorker(chunk, config);
Thread workerThread = new Thread(worker, "Worker-" + chunk.getChunkId());
-
workerThreads.add(workerThread);
- // TODO:
- // Students may print helpful debug information here,
- // for example which chunk is assigned to which worker thread.
+ System.out.println("Assigned Chunk " + chunk.getChunkId() + " to " + workerThread.getName());
}
- // 4. Create and start monitor thread
ProgressMonitor monitor = new ProgressMonitor(config, chunks);
Thread monitorThread = new Thread(monitor, "Progress-Monitor");
+ monitorThread.start();
- // TODO:
- // Start the monitor thread before starting the workers
- // so that progress can be displayed while downloading happens.
- //
- // Example idea:
- // monitorThread.start();
+ for (Thread thread : workerThreads) {
+ thread.start();
+ }
- // 5. Start worker threads
- // TODO:
- // Start each worker thread in workerThreads.
- // Use a loop and call start() on each thread.
+ try {
+ for (Thread thread : workerThreads) {
+ thread.join();
+ }
+ monitorThread.join();
+ } catch (InterruptedException e) {
+ System.err.println("Main thread interrupted while waiting for workers.");
+ }
- // 6. Wait for workers to finish
- // TODO:
- // Wait for all worker threads to complete by calling join().
- // This should be done inside a try-catch block for InterruptedException.
- //
- // Hint:
- // for (Thread thread : workerThreads) {
- // thread.join();
- // }
-
- // TODO:
- // After all workers finish, the monitor thread may also need to stop.
- // Depending on how ProgressMonitor is implemented, students may:
- // - wait for it to finish on its own, or
- // - add a stopping mechanism in ProgressMonitor later.
- //
- // If your monitor finishes automatically, you may join it here.
-
- // NOTE:
- // this final report may show 0 progress because no worker has actually run yet.
- // Until students complete the thread start/join TODOs above,
-
- // 7. Print final report
System.out.println();
System.out.println("=== Final Report ===");
@@ -86,22 +58,20 @@ public class Main {
for (ChunkStatus chunk : chunks) {
downloadedMB += chunk.getDownloadedMB();
-
if (chunk.isCompleted()) {
completedChunks++;
}
- System.out.println(
- "Chunk " + chunk.getChunkId()
- + ": " + chunk.getDownloadedMB()
- + "/" + chunk.getChunkSizeMB()
- + " MB"
- );
+ System.out.printf("Chunk %d: %.2f/%.2f MB (Duration: %d ms)%n",
+ chunk.getChunkId(),
+ chunk.getDownloadedMB(),
+ chunk.getChunkSizeMB(),
+ chunk.getDownloadDurationMs());
}
System.out.println();
System.out.println("Completed chunks: " + completedChunks + "/" + chunks.size());
- System.out.println("Downloaded total: " + downloadedMB + "/" + config.getTotalSizeMB() + " MB");
+ System.out.printf("Downloaded total: %.2f/%d MB%n", downloadedMB, config.getTotalSizeMB());
System.out.println("Simulation finished.");
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/ProgressMonitor.java b/src/main/java/ProgressMonitor.java
index 475c0e0..4ae33e8 100644
--- a/src/main/java/ProgressMonitor.java
+++ b/src/main/java/ProgressMonitor.java
@@ -16,33 +16,18 @@ public class ProgressMonitor implements Runnable {
@Override
public void run() {
- // TODO:
- // Repeatedly check chunk progress until all chunks are completed.
- // In each loop:
- // 1. Read the downloaded size from every chunk
- // 2. Add all downloaded amounts to totalDownloadedMB
- // 3. Count completed chunks
- // 4. Print a progress message
- // 5. If completedChunks == chunks.size(), print a final monitor message and stop
- // 6. Otherwise sleep for monitorDelayMs and continue
-
-
while (true) {
double totalDownloadedMB = 0.0;
int completedChunks = 0;
for (ChunkStatus chunk : chunks) {
totalDownloadedMB += chunk.getDownloadedMB();
-
if (chunk.isCompleted()) {
completedChunks++;
}
}
- double percent = 0.0;
- if (totalSizeMB > 0) {
- percent = (totalDownloadedMB * 100.0) / totalSizeMB;
- }
+ double percent = (totalSizeMB > 0) ? (totalDownloadedMB * 100.0) / totalSizeMB : 100.0;
System.out.printf(
"Progress for %s: %.1f/%.1f MB (%.2f%%), completed chunks: %d/%d%n",
@@ -54,9 +39,10 @@ public class ProgressMonitor implements Runnable {
chunks.size()
);
-
- // TODO:
- // If all chunks are completed, print a final message and exit the loop
+ if (completedChunks == chunks.size()) {
+ System.out.println("Monitor: All chunks completed. Shutting down monitor...");
+ break;
+ }
try {
Thread.sleep(monitorDelayMs);
@@ -66,4 +52,4 @@ public class ProgressMonitor implements Runnable {
}
}
}
-}
+}
\ No newline at end of file