Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37b270128e | ||
|
|
c4f038a5d7 |
@@ -0,0 +1,80 @@
|
||||
Question 1: start() vs run()
|
||||
|
||||
What output do you get from the program? Why?
|
||||
output:
|
||||
|
||||
Calling run()
|
||||
Running in: main
|
||||
Calling start()
|
||||
Running in: Thread-2
|
||||
|
||||
When we call the run() method, no new thread is created, and the code is executed within the main thread. However, when we call the start() method, the JVM creates a new thread and executes the run() method inside that thread.
|
||||
|
||||
What’s the difference in behavior between calling start() and run()?
|
||||
|
||||
The run() method does not create a new thread and executes in the current thread, while the start() method creates a new thread and runs the task concurrently in that thread.
|
||||
|
||||
Question 2: Daemon Threads
|
||||
Code
|
||||
|
||||
What output do you get from the program? Why?
|
||||
|
||||
outpot:
|
||||
Main thread ends.
|
||||
|
||||
sometime before end of program: Daemon thread running...
|
||||
|
||||
The reason is that the thread we created is a Daemon thread. Daemon threads are used for background tasks and do not prevent the JVM from shutting down. As soon as the main thread finishes, the JVM terminates, and all Daemon threads are stopped as well.
|
||||
|
||||
What happens if you remove thread.setDaemon(true)?
|
||||
|
||||
If we remove thread.setDaemon(true), the created thread will no longer be a Daemon thread and will become a regular (User) thread.
|
||||
|
||||
In this case, the JVM waits for the thread to finish its execution before shutting down. Therefore, the message:
|
||||
|
||||
Daemon thread running...
|
||||
|
||||
will be printed 20 times, and then the program will terminate.
|
||||
|
||||
What are some real-life use cases of daemon threads?
|
||||
|
||||
Daemon threads are usually used for background tasks, such as:
|
||||
|
||||
Garbage Collection in the JVM.
|
||||
Logging.
|
||||
Auto-saving files.
|
||||
Monitoring system status.
|
||||
Cleaning temporary cache data.
|
||||
Checking the status of networks and services.
|
||||
|
||||
These tasks help the program run more efficiently, but they are not important enough to keep the application alive. Therefore, once all user threads have finished, the JVM can shut down without waiting for daemon threads to complete.
|
||||
|
||||
Question 3: A shorter way to create threads
|
||||
Code
|
||||
|
||||
What output do you get from the program?
|
||||
|
||||
output:Thread is running using a ...!
|
||||
|
||||
What is the () -> { ... } syntax called?
|
||||
|
||||
This structure is called a Lambda Expression.
|
||||
|
||||
A Lambda Expression provides a shorter and more readable way to implement functional interfaces such as Runnable.
|
||||
|
||||
In this example, the Lambda Expression actually contains the code that would normally be placed inside the run() method. Instead of creating a separate class and implementing run(), we can write the implementation directly using a Lambda Expression.
|
||||
|
||||
How is this code different from creating a class that extends Thread or implements Runnable?
|
||||
|
||||
In the traditional approach, we had to create a separate class that either extends Thread or implements Runnable. This makes the code longer and more verbose.
|
||||
|
||||
By using a Lambda Expression, we can achieve the same result with much shorter and cleaner code.
|
||||
|
||||
Advantages of Lambda Expressions:
|
||||
|
||||
Less code
|
||||
Better readability
|
||||
Easier maintenance
|
||||
Suitable for short and simple thread tasks
|
||||
|
||||
However, there is no performance difference between a Lambda Expression and a regular Runnable implementation. The main benefit is simpler and more readable code.
|
||||
@@ -21,23 +21,49 @@ public class DownloadWorker implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO: Record the chunk start time in chunkStatus.
|
||||
chunkStatus.setStartTimeMs(System.currentTimeMillis());
|
||||
|
||||
System.out.println("Chunk " + chunkStatus.getChunkId() + " started downloading.");
|
||||
|
||||
double downloaded = 0.0;
|
||||
|
||||
// TODO: Print a message that this chunk has 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 minDelay = config.getMinStepDelayMs();
|
||||
int maxDelay = config.getMaxStepDelayMs();
|
||||
int delay = random.nextInt(maxDelay - minDelay + 1) + minDelay;
|
||||
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
double minStep = config.getMinStepDownloadMB();
|
||||
double maxStep = config.getMaxStepDownloadMB();
|
||||
double step = minStep + (maxStep - minStep) * random.nextDouble();
|
||||
|
||||
downloaded += step;
|
||||
|
||||
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("Chunk " + chunkStatus.getChunkId() + " finished downloading.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+20
-31
@@ -34,48 +34,37 @@ public class Main {
|
||||
|
||||
workerThreads.add(workerThread);
|
||||
|
||||
// TODO:
|
||||
// Students may print helpful debug information here,
|
||||
// for example which chunk is assigned to which worker thread.
|
||||
// Debug info
|
||||
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");
|
||||
|
||||
// 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();
|
||||
// }
|
||||
try {
|
||||
for (Thread thread : workerThreads) {
|
||||
thread.join();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Main thread interrupted while waiting for workers.");
|
||||
}
|
||||
|
||||
// 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,
|
||||
// Wait for monitor to finish (optional but better)
|
||||
try {
|
||||
monitorThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Main thread interrupted while waiting for monitor.");
|
||||
}
|
||||
|
||||
// 7. Print final report
|
||||
System.out.println();
|
||||
|
||||
@@ -16,16 +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;
|
||||
@@ -54,9 +44,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("Download completed successfully for " + fileName);
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(monitorDelayMs);
|
||||
|
||||
Reference in New Issue
Block a user