Develop #1
+135
@@ -0,0 +1,135 @@
|
||||
|
||||
### 1. `start()` vs `run()`
|
||||
|
||||
```java
|
||||
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:**
|
||||
|
||||
- ##### What output do you get from the program? Why?
|
||||
|
||||
|
||||
- ##### What’s the difference in behavior between calling `start()` and `run()`?</br>
|
||||
|
||||
|
||||
**answers :**
|
||||
|
||||
```
|
||||
Calling run()
|
||||
Running in: main
|
||||
Calling start()
|
||||
Running in: Thread-2
|
||||
```
|
||||
Because when we call " **t1.run()** ", it does not create a new thread. we have just called run method in class main so it prints "**Running in: main**".
|
||||
</br>
|
||||
But when we call " **t2.start()** " it creates a new thread and it calls the run method of this object on the new thread so it prints "**Running in: Thread-2**"
|
||||
|
||||
---
|
||||
### 2. Daemon Threads
|
||||
```java
|
||||
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:**
|
||||
- ##### What output do you get from the program? Why?
|
||||
|
||||
**answer :**
|
||||
|
||||
output :
|
||||
```
|
||||
Main thread ends.
|
||||
Daemon thread running...
|
||||
```
|
||||
because the Main Thread finishes quickly but the Daemon tries to print messages for 20 times so the JVM kills the Daemon Thread abruptly, even if it hasn’t finished its work.
|
||||
|
||||
|
||||
- ##### What happens if you remove `thread.setDaemon(true)`?
|
||||
|
||||
|
||||
**answer :**</br>
|
||||
Even though the main thread finishes, the JVM keeps the program running until the new User Thread completes its 20 iterations. The full output will be printed.
|
||||
- ##### What are some real-life use cases of daemon threads?</br>
|
||||
|
||||
|
||||
**answer :**</br>
|
||||
- _**Garbage Collection:**_</br>
|
||||
The JVM itself uses daemon threads for memory cleanup. They run in the background to free up occupied memory so the main application can continue running smoothly.
|
||||
- **_Logging:_**</br>
|
||||
Threads that write log messages to files are often daemons. This ensures that if the main application shuts down abruptly, the logging process doesn’t block it or cause delays.
|
||||
- **_Health Checks:_**</br>
|
||||
Services that periodically check if the system is healthy (such as verifying database connectivity) usually run as daemon threads.
|
||||
- **_Pre-loading:_**</br>
|
||||
When an application is starting up, daemon threads can prepare necessary data in advance. This helps improve the speed and responsiveness of the application once it’s fully loaded.
|
||||
|
||||
---
|
||||
|
||||
### 3. A shorter way to create threads
|
||||
|
||||
```java
|
||||
public class ThreadDemo {
|
||||
public static void main(String[] args) {
|
||||
Thread thread = new Thread(() -> {
|
||||
System.out.println("Thread is running using a ...!");
|
||||
});
|
||||
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Questions:**
|
||||
|
||||
- ##### What output do you get from the program?
|
||||
|
||||
**answer:**</br>
|
||||
output:
|
||||
```
|
||||
Thread is running using a ...!
|
||||
```
|
||||
|
||||
- ##### What is the `() -> { ... }` </br>
|
||||
|
||||
**answer:**</br>
|
||||
This syntax is called a Lambda Expression. It provides a concise way to represent instances of functional interfaces (interfaces with only one abstract method).
|
||||
- #### How is this code different from creating a class that extends `Thread` or implements `Runnable`?
|
||||
|
||||
**answer:**</br>
|
||||
**Less Code:** With Lambda, you don’t need to create a separate class (either extending Thread or implementing Runnable) and override the run() method. You write the logic directly inside the Thread constructor.
|
||||
|
||||
**Flexibility:** While extending Thread forces you to create a new class hierarchy, and implementing Runnable requires an extra class or anonymous inner class, Lambda allows you to pass the behavior directly as an argument.
|
||||
@@ -21,23 +21,32 @@ 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] Start downloading for " + chunkStatus.getChunkId());
|
||||
|
||||
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.
|
||||
long sleepTime = (long) config.getMinStepDelayMs() + (long) (random.nextDouble() * (config.getMaxStepDelayMs() - config.getMinStepDelayMs()));
|
||||
|
||||
try {
|
||||
Thread.sleep(sleepTime);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
double stepSize = config.getMinStepDownloadMB() + (random.nextDouble() * (config.getMaxStepDownloadMB() - config.getMinStepDownloadMB()));
|
||||
|
||||
downloaded += stepSize;
|
||||
|
||||
if (downloaded > chunkStatus.getChunkSizeMB()) downloaded = chunkStatus.getChunkSizeMB();
|
||||
|
||||
chunkStatus.setDownloadedMB(downloaded);
|
||||
System.out.println("Chunk " + chunkStatus.getChunkId() + " progress: " + downloaded + "/" + chunkStatus.getChunkSizeMB());
|
||||
}
|
||||
|
||||
// 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] Finished download for " + chunkStatus.getChunkId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-38
@@ -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<ChunkStatus> chunks = ChunkUtils.createChunks(
|
||||
config.getTotalSizeMB(),
|
||||
config.getChunkCount()
|
||||
);
|
||||
|
||||
// 3. Create worker threads
|
||||
List<Thread> workerThreads = new ArrayList<>();
|
||||
|
||||
for (ChunkStatus chunk : chunks) {
|
||||
@@ -34,50 +31,38 @@ 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("[Main] Assigned chunk ID " + chunk.getChunkId() +
|
||||
" (Size: " + chunk.getChunkSizeMB() + " MB) to " + workerThread.getName());
|
||||
}
|
||||
|
||||
// 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();
|
||||
System.out.println("[Main] Monitor thread started");
|
||||
|
||||
// 5. Start worker threads
|
||||
// TODO:
|
||||
// Start each worker thread in workerThreads.
|
||||
// Use a loop and call start() on each thread.
|
||||
for (Thread workerThread : workerThreads) {
|
||||
workerThread.start();
|
||||
}
|
||||
System.out.println("[Main] All worker threads started.");
|
||||
|
||||
// 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();
|
||||
// }
|
||||
try {
|
||||
for (Thread thread : workerThreads) {
|
||||
thread.join();
|
||||
}
|
||||
System.out.println("[Main] All workers finished.");
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("[Main] 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();
|
||||
System.out.println("[Main] Monitor finished.");
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("[Main] Main thread interrupted while waiting for monitor.");
|
||||
}
|
||||
|
||||
// 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 ===");
|
||||
|
||||
|
||||
@@ -16,16 +16,7 @@ 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
|
||||
|
||||
System.out.println("[Monitor] Started monitoring progress...");
|
||||
|
||||
while (true) {
|
||||
double totalDownloadedMB = 0.0;
|
||||
@@ -54,9 +45,11 @@ 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 downloaded successfully!");
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(monitorDelayMs);
|
||||
|
||||
Reference in New Issue
Block a user