This commit is contained in:
2026-06-19 22:25:59 +03:30
parent 9e5c715088
commit 69fdb3fae5
4 changed files with 84 additions and 56 deletions
+35
View File
@@ -0,0 +1,35 @@
start() vs run() :
What output do you get from the program? Why?
وقتی متد run() رو مستقیماً روی آبجکت صدا می‌زنیم، هیچ Thread جدیدی ساخته نمیشه. در واقع کد ما دقیقاً روی همون Thread اجراکننده فعلی (یعنی main) مثل یه متد معمولی اجرا میشه و تا تموم نشه، برنامه به خط بعدی نمیره
اما وقتی start() رو فراخوانی می‌کنیم، از ماشین مجازی جاوا می‌خوایم که یک Thread کاملاً جدید در سیستم‌عامل بسازه و متد run() رو به صورت موازی داخل اون Thread جدید اجرا کنه.
Whats the difference in behavior between calling start() and run()?
متد start() چرخه حیات یک Thread جدید رو آغاز می‌کنه و امکان اجرای موازی رو به ما میده، ولی run() صرفاً یک فراخوانی متد ساده است و هیچ موازی‌سازی‌ای در کار نیست.
------------------------------------
Daemon Threads :
What output do you get from the program? Why?
توی جاوا، به محض اینکه کار تمام تردهای اصلی یا اصطلاحاً User Threadها تموم بشه، JVM برنامه رو می‌بنده و دیگه منتظر تردهای پس‌زمینه (Daemon) نمی‌مونه. اینجا چون کار ترد main خیلی سریع تموم میشه، برنامه هم بلافاصله بسته میشه و اجازه نمیده حلقه ۲۰ تایی ترد Daemon کامل بشه.
What happens if you remove thread.setDaemon(true)?
با این کار، ترد ما تبدیل به یک User Thread معمولی میشه. در این حالت، حتی اگه ترد main به پایان برسه، برنامه باز می‌مونه و منتظر میشه تا حلقه ۲۰ تایی (که حدود ۱۰ ثانیه زمان می‌بره) به طور کامل اجرا بشه و بعد از اون به صورت عادی بسته میشه.
What are some real-life use cases of daemon threads?
زباله‌روب جاوا (Garbage Collector): تو پس‌زمینه اجرا میشه و حافظه‌های بی‌استفاده رو آزاد می‌کنه.
ذخیره خودکار (Auto-Save): توی ادیتورهای کد یا نرم‌افزارهایی مثل Word برای ذخیره فایل‌ها در پس‌زمینه بدون ایجاد وقفه تو کار کاربر.
مانیتورینگ و Heartbeat: تردهایی که تو برنامه‌های شبکه‌ای، سلامت سیستم یا اتصال به سرور رو به صورت مداوم چک می‌کنن.
------------------------------------
A shorter way to create threads :
What output do you get from the program?
Thread is running using a ...!
What is the () -> { ... } syntax called?
به این سینتکس عبارت لامبدا (Lambda Expression) می‌گیم.
How is this code different from creating a class that extends Thread or implements Runnable?
به جای اینکه بیایم یه کلاس جداگانه بسازیم و کلی کد تکراری بنویسیم تا فقط متد run رو بازنویسی (Override) کنیم، با استفاده از لامبدا می‌تونیم مستقیماً منطق و بدنه متد رو پاس بدیم.
+26 -11
View File
@@ -21,23 +21,38 @@ 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.");
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("Worker-" + chunkStatus.getChunkId() + " was interrupted.");
Thread.currentThread().interrupt();
return;
}
double stepDownload = config.getMinStepDownloadMB() +
(config.getMaxStepDownloadMB() - config.getMinStepDownloadMB()) * random.nextDouble();
downloaded += stepDownload;
if (downloaded > chunkStatus.getChunkSizeMB()) {
downloaded = chunkStatus.getChunkSizeMB();
}
chunkStatus.setDownloadedMB(downloaded);
}
// 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.");
}
}
+18 -31
View File
@@ -39,45 +39,32 @@ public class Main {
// for example which chunk is assigned to which worker thread.
}
// 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 thread : workerThreads) {
thread.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 thread : workerThreads) {
try {
thread.join();
} catch (InterruptedException e) {
System.out.println("Main thread interrupted while waiting for workers.");
Thread.currentThread().interrupt();
}
}
// 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.
try {
monitorThread.join();
} catch (InterruptedException e) {
System.out.println("Main thread interrupted while waiting for Monitor.");
Thread.currentThread().interrupt();
}
// 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 ===");
+5 -14
View File
@@ -16,17 +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;
int completedChunks = 0;
@@ -54,14 +43,16 @@ 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("All chunks downloaded. Monitor shutting down.");
break;
}
try {
Thread.sleep(monitorDelayMs);
} catch (InterruptedException e) {
System.out.println("Progress monitor interrupted.");
Thread.currentThread().interrupt();
return;
}
}