diff --git a/Report.md b/Report.md
new file mode 100644
index 0000000..ab740f1
--- /dev/null
+++ b/Report.md
@@ -0,0 +1,124 @@
+## 1 . `start()` vs `run()` :
+
+```
+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();
+ }
+}
+```
+### Questions and Answers:
+* **What output do you get from the program? Why?**
+ * ```
+ //output:
+ Calling run()
+ Running in : main
+ Calling start()
+ Running in : Thread-2
+ ```
+ * *When `t1.run()` is called directly, it executes the `run()` method in the current thread (the main thread), just like a normal method call. No new thread is created. Therefore, `Thread.currentThread().getName()` returns `"main"`.*
+
+ * *When `t2.start()` is called, it creates a new thread named `"Thread-2"` and the JVM automatically invokes the `run()` method inside that new thread. Hence, `Thread.currentThread().getName()` returns `"Thread-2"`.*
+
+* **What’s the difference in behavior between calling `start()` and `run()`?**
+
+ * *Calling `run()` directly just executes the code inside `run()` in the caller's thread – it's not multithreading.*
+
+ * *Calling `start()` schedules the thread to run, and the `run()` method will be executed in a separate thread concurrently.*
+
+***
+
+## 2. Daemon Threads :
+```
+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.");
+ }
+}
+```
+### Questions and Answers:
+
+* **What output do you get from the program? Why?**
+ * ```
+ //output:
+ Main thread ends.
+ Daemon thread running...
+ Daemon thread running...
+ ...
+ //(less than 20 times)
+ ```
+ * *The main thread prints `"Main thread ends."` and then terminates.*
+
+ * *The other thread is a `daemon thread`. Daemon threads are background threads that do not prevent the JVM from exiting.*
+
+ * *When the last non-daemon thread (in this case, only the main thread) finishes, the JVM terminates immediately without waiting for the daemon thread to complete its loop.*
+
+ * *Therefore, the daemon thread only gets to print a few lines before the program shuts down. It never reaches 20 iterations.*
+
+* **What happens if you remove thread.setDaemon(true)?**
+
+ * *The thread prints 20 times and then the program ends, because the thread is no longer a daemon (it becomes a regular user thread).*
+* **What are some real-life use cases of daemon threads?**
+
+ 1. *Background music in a game – While you play, music plays in the background. When you close the game, the music stops immediately. No need to finish the song.*
+
+ 2. *Auto-save in a text editor – Every few minutes, the program saves your file automatically. If you close the program, it doesn't matter if the auto-save finishes or not. Just stop.*
+
+
+***
+
+## 3. A shorter way to create threads :
+```
+public class ThreadDemo {
+ public static void main(String[] args) {
+ Thread thread = new Thread(() -> {
+ System.out.println("Thread is running using a ...!");
+ });
+
+ thread.start();
+ }
+}
+```
+### Questions and Answers:
+
+* **What output do you get from the program?**
+ * ```
+ //output:
+ Thread is running using a ...!
+ ```
+* **What is the `() -> { ... }` syntax called?**
+
+ * *It is called a Lambda Expression*
+
+* **How is this code different from creating a class that extends `Thread` or implements `Runnable`?**
+
+ * *Shorter and cleaner code.*
+ * *No need for a separate class or explicit `run()` override.*
+ * *Lambda directly provides the `run()` body.*
\ No newline at end of file
diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java
index 546de2d..021ed56 100644
--- a/src/main/java/DownloadWorker.java
+++ b/src/main/java/DownloadWorker.java
@@ -21,23 +21,48 @@ 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(Thread.currentThread().getName() + " started downloading chunk " +
+ chunkStatus.getChunkId() + " (" + 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.
+ int delayMs = config.getMinStepDelayMs() +
+ random.nextInt(config.getMaxStepDelayMs() - config.getMinStepDelayMs() + 1);
+ try {
+ Thread.sleep(delayMs);
+ } catch (InterruptedException e) {
+ System.out.println(Thread.currentThread().getName() + " interrupted");
+ return;
+ }
+
+ // Generate random download amount for this step
+ double step = config.getMinStepDownloadMB() +
+ random.nextDouble() * (config.getMaxStepDownloadMB() - config.getMinStepDownloadMB());
+ downloaded += step;
+ if (downloaded > chunkStatus.getChunkSizeMB()) {
+ downloaded = chunkStatus.getChunkSizeMB();
+ }
+
+ // Update shared status
+ chunkStatus.setDownloadedMB(downloaded);
+
+ // Optional step progress print
+ System.out.printf("%s: chunk %d -> %.2f / %.2f MB (%.1f%%)%n",
+ Thread.currentThread().getName(),
+ chunkStatus.getChunkId(),
+ downloaded,
+ chunkStatus.getChunkSizeMB(),
+ (downloaded / chunkStatus.getChunkSizeMB()) * 100);
}
- // 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(Thread.currentThread().getName() + " FINISHED chunk " +
+ chunkStatus.getChunkId() + " in " +
+ (chunkStatus.getEndTimeMs() - chunkStatus.getStartTimeMs()) + " ms");
}
}
diff --git a/src/main/java/Main.java b/src/main/java/Main.java
index 82bd239..ddd1ba0 100644
--- a/src/main/java/Main.java
+++ b/src/main/java/Main.java
@@ -34,48 +34,35 @@ public class Main {
workerThreads.add(workerThread);
- // TODO:
- // Students may print helpful debug information here,
- // for example which chunk is assigned to which worker thread.
+ System.out.println("Created " + workerThread.getName() +
+ " for chunk " + chunk.getChunkId() +
+ " (size: " + chunk.getChunkSizeMB() + " MB)");
}
// 4. Create and start monitor thread
ProgressMonitor monitor = new ProgressMonitor(config, chunks);
Thread monitorThread = new Thread(monitor, "Progress-Monitor");
-
- // TODO:
- // Start the monitor thread before starting the workers
- // so that progress can be displayed while downloading happens.
- //
- // 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 t : workerThreads) {
+ t.start();
+ }
// 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();
- // }
+ for (Thread t : workerThreads) {
+ try {
+ t.join();
+ } catch (InterruptedException e) {
+ System.out.println("Main interrupted while waiting for workers.");
+ }
+ }
- // 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,
+ try {
+ monitorThread.join();
+ } catch (InterruptedException e) {
+ System.out.println("Main interrupted while waiting for monitor.");
+ }
// 7. Print final report
System.out.println();
diff --git a/src/main/java/ProgressMonitor.java b/src/main/java/ProgressMonitor.java
index 475c0e0..428b7d2 100644
--- a/src/main/java/ProgressMonitor.java
+++ b/src/main/java/ProgressMonitor.java
@@ -16,16 +16,6 @@ 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;
@@ -55,8 +45,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 completed. Monitor thread stopping.");
+ break;
+ }
try {
Thread.sleep(monitorDelayMs);
diff --git a/src/main/resources/download_config.txt b/src/main/resources/download_config.txt
index 6ddd6ca..0ab0be3 100644
--- a/src/main/resources/download_config.txt
+++ b/src/main/resources/download_config.txt
@@ -1,7 +1,7 @@
-fileName=movie.mkv
-totalSizeMB=120
-chunkCount=6
-minStepDelayMs=80
-maxStepDelayMs=200
-minStepDownloadMB=2
-maxStepDownloadMB=6
\ No newline at end of file
+ fileName=movie.mkv
+ totalSizeMB=120
+ chunkCount=6
+ minStepDelayMs=80
+ maxStepDelayMs=200
+ minStepDownloadMB=2
+ maxStepDownloadMB=6
\ No newline at end of file