From 69fdb3fae5d36f077dbd3e7478dfb09c69e9ff8f Mon Sep 17 00:00:00 2001 From: SoroushZ Date: Fri, 19 Jun 2026 22:25:59 +0330 Subject: [PATCH] 8T --- Rp.md | 35 +++++++++++++++++++++ src/main/java/DownloadWorker.java | 37 +++++++++++++++------- src/main/java/Main.java | 49 +++++++++++------------------- src/main/java/ProgressMonitor.java | 19 +++--------- 4 files changed, 84 insertions(+), 56 deletions(-) create mode 100644 Rp.md diff --git a/Rp.md b/Rp.md new file mode 100644 index 0000000..09b4c0a --- /dev/null +++ b/Rp.md @@ -0,0 +1,35 @@ +start() vs run() : +What output do you get from the program? Why? +وقتی متد run() رو مستقیماً روی آبجکت صدا می‌زنیم، هیچ Thread جدیدی ساخته نمیشه. در واقع کد ما دقیقاً روی همون Thread اجراکننده فعلی (یعنی main) مثل یه متد معمولی اجرا میشه و تا تموم نشه، برنامه به خط بعدی نمیره +اما وقتی start() رو فراخوانی می‌کنیم، از ماشین مجازی جاوا می‌خوایم که یک Thread کاملاً جدید در سیستم‌عامل بسازه و متد run() رو به صورت موازی داخل اون Thread جدید اجرا کنه. + +What’s 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) کنیم، با استفاده از لامبدا می‌تونیم مستقیماً منطق و بدنه متد رو پاس بدیم. diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java index 546de2d..73a1c1b 100644 --- a/src/main/java/DownloadWorker.java +++ b/src/main/java/DownloadWorker.java @@ -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."); } } diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 82bd239..9b25180 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -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 ==="); diff --git a/src/main/java/ProgressMonitor.java b/src/main/java/ProgressMonitor.java index 475c0e0..483c5da 100644 --- a/src/main/java/ProgressMonitor.java +++ b/src/main/java/ProgressMonitor.java @@ -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; } }