diff --git a/report.md b/report.md new file mode 100644 index 0000000..25ada07 --- /dev/null +++ b/report.md @@ -0,0 +1,20 @@ + +خروجی برنامه به این شکل است: اول خط Calling run چاپ میشود، بعد خط Running in: main، بعد خط Calling start و در نهایت خط Running in: Thread-2. + +دلیلش این است که وقتی ران را صدا میزنیم، اصلاً ترد جدیدی ساخته نمیشود. متد ران دقیقاً مثل یک متد معمولی در همان ترد فعلی که اینجا همان مین است اجرا میشود. اما وقتی استارت را میزنیم، جاوا یک ترد جدید در پسزمینه به اسم Thread-2 میسازد و متد ران را میاندازد آنجا تا اجرا شود. + +فرق اصلی این دو در این است که وقتی ران را صدا میزنیم، کار کاملاً همگام پیش میرود. یعنی برنامه همانجا میایستد تا اجرای متد تمام شود و بعد میرود خط بعدی. اما وقتی استارت را صدا میزنیم، کار ناهمگام میشود. یک ترد جدید ساخته میشود و کار را میسپارد به آن، برنامه هم دیگر معطل نمیماند و سریع میرود سراغ اجرای خط بعدی. + +خروجی برنامه احتمالاً فقط یک خط است که مینویسد مین ترد اندز. + +دلیلش این است که در جاوا ما کلاً دو مدل ترد داریم یکی تردهای معمولی و یکی تردهای دیمون. ماشین مجازی جاوا اصلاً منتظر تمام شدن کار تردهای دیمون نمیماند. یعنی به محض اینکه کار تردهای اصلی تمام شود، برنامه را میبندد و تردهای دیمون در هر وضعیتی که باشند درجا قطع میشوند. + +اگر خط مربوط به تنظیم دیمون را پاک کنیم، ترد ما تبدیل میشود به یک ترد معمولی. آن وقت ماشین مجازی مجبور است صبر کند تا حلقه به طور کامل تمام شود و تازه بعدش برنامه بسته میشود. + +این تردها در دنیای واقعی بیشتر برای کارهای پسزمینه استفاده میشوند که خیلی حیاتی نیستند ولی باید باشند. مثلاً سیستم تمیزکننده حافظه جاوا که خودش در پسزمینه حافظه را پاک میکند، یا قابلیت ذخیره خودکار در برنامهها که هر چند دقیقه یک بار خودکار تغییرات را ذخیره میکنند. + +خروجی برنامه به این صورت است که پیام اجرای ترد با استفاده از لامبدا چاپ میشود. + +به این مدل کد زدن عبارت لامبدا میگویند که از نسخه هشت جاوا به بعد اضافه شد. + +فرق این روش با ساختن کلاسی که از کلاس ترد ارثبری میکند در این است که خیلی خلاصهتر و جمعوجورتر است. دیگر نیازی نیست کلی کد اضافه بنویسیم یا یک کلاس جدا بسازیم و متد ران را بازنویسی کنیم. منطق کد را خیلی راحت همانجا مینویسیم. اینطوری کد خیلی تمیزتر و خواناتر میشود، مخصوصاً برای وقتهایی که فقط میخواهیم یک تکه کد کوچک را سریع در یک ترد اجرا کنیم. diff --git a/src/main/java/DownloadWorker.java b/src/main/java/DownloadWorker.java index 546de2d..d0d6604 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,36 @@ public class DownloadWorker implements Runnable { @Override public void run() { - // TODO: Record the chunk start time in chunkStatus. + chunkStatus.setStartTimeMs(System.currentTimeMillis()); + System.out.println(Thread.currentThread().getName() + " started downloading."); + double downloaded = 0.0; + double chunkSize = chunkStatus.getChunkSizeMB(); - // TODO: Print a message that this chunk has started downloading. + while (downloaded < chunkSize) { + int delayMs = config.getMinStepDelayMs() + random.nextInt(config.getMaxStepDelayMs() - config.getMinStepDelayMs() + 1); - 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 { + Thread.sleep(delayMs); + } catch (InterruptedException e) { + System.out.println(Thread.currentThread().getName() + " was interrupted."); + return; + } + + double stepDownload = config.getMinStepDownloadMB() + (config.getMaxStepDownloadMB() - config.getMinStepDownloadMB()) * random.nextDouble(); + downloaded += stepDownload; + + if (downloaded > chunkSize) { + downloaded = chunkSize; + } + + 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(Thread.currentThread().getName() + " finished downloading."); } -} +} \ No newline at end of file diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 82bd239..134373a 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,13 +18,11 @@ public class Main { System.out.println("Chunk count: " + config.getChunkCount()); System.out.println(); - // 2. Create chunks List