Add Report.md #2

Merged
Meraj merged 2 commits from develop into main 2026-07-31 23:31:05 +00:00
4 changed files with 93 additions and 90 deletions
+43
View File
@@ -0,0 +1,43 @@
**Question 1**
1- This is the output for the program:
``` Text
Calling run()
Running in: main
Calling start()
Running in: Thread-2
```
2- `t1.run()` will run the method from the thread that it is called from, which is `main` here. It does not create any new thread.
<br />
calling `t2.start()` will create a new thread (which is named `thread-2` here).
<hr />
**Question 2**
1- This is the output for the program:
``` Text
Main thread ends.
```
This happens because when the `main` thread is done and there is no other `User` thread running, then all of the `Daemon` threads will terminate.
2- If you remove that line, the thread becomes a `User` thread (the default).
*Behavior*:
The program will print "Main thread ends."
However, the JVM will not exit.
It will keep running for approximately 10 seconds until the DaemonRunnable finishes all 20 iterations of its loop.
Only after the run() method of that thread completes will the JVM shut down.
3- Some real-life use cases of daemon threads are background tasks that need to be automatically closed after the main application shuts down like `garbage collectors` and `spell checkers` or `auto saves`.
<hr />
**Question 3**
1- This is the output for the program:
``` Text
Thread is running using a ...!
```
2- It is called a `lambda expression`.
3- This is much more concise. But lacks the maintainability which class method provides.
+24 -20
View File
@@ -1,12 +1,5 @@
import java.util.Random;
/**
* Simulates downloading a single chunk of a file.
*
* <p>This class is intentionally provided as a skeleton for students.
* The main multithreading and simulation logic should be completed
* in the run() method.</p>
*/
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.");
}
}
+20 -50
View File
@@ -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<ChunkStatus> chunks = ChunkUtils.createChunks(
config.getTotalSizeMB(),
config.getChunkCount()
);
// 3. Create worker threads
List<Thread> 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.");
}
}
}
+6 -20
View File
@@ -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 {
}
}
}
}
}