Merge pull request 'Complete assignment' (#1) from develop into main

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-07-18 17:10:19 +00:00
5 changed files with 99 additions and 56 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="25" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+51
View File
@@ -0,0 +1,51 @@
## Question 1
output:
```angular2html
Calling run()
Running in: main
Calling start()
Running in: Thread-2
```
note that there will be a 100ms pause before calling start.
when calling `t1.run()` no other thread will be created and `Thread.currentThread().getName()` returns the thread that was already running.
but when calling `t2.start()` a branch new thread gets created alongside the main one named _Thread-2_.
## Question 2
output:
```angular2html
Main thread ends.
Daemon thread running...
```
when we use `setDaemon(true)` method for a thread it means that there is no need for _JVM_ to wait for this thread to finish its job and end the program.
So if we call `thread.start()` after setting the thread a daemon one a new daemon thread gets created and as soon as there is time for the main thread (because of the 0.5 second pause) it finishes the program.
If we were not to set the thread a daemon, we could see the expression `Daemon thread running...` 20 times which 0.5 second pauses.
It is useful for health check and monitoring, cache eviction etc...
## Question 3
output:
```angular2html
Thread is running using a ...!
```
`() -> { ... }` is called a _Lambda Expression_.
If we were to write this functionality in a simple way and not in lambda:
```java
public class ThreadDemo {
static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running using a ...!");
}
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
```
+22 -11
View File
@@ -21,23 +21,34 @@ 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(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 delay = config.getMinStepDelayMs() + random.nextInt(config.getMaxStepDelayMs() - config.getMinStepDelayMs() + 1);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// TODO: Mark the chunk as completed.
// TODO: Record the chunk end time in chunkStatus.
// TODO: Print a message that this chunk has finished downloading.
double downloadAmount = random.nextDouble(chunkStatus.getChunkSizeMB());
downloaded += downloadAmount;
if(downloaded > chunkStatus.getChunkSizeMB())
downloaded = chunkStatus.getChunkSizeMB();
chunkStatus.setDownloadedMB(downloaded);
System.out.printf("%s progress: %.2f / %.2f MB\n",
chunkStatus.getChunkId(), downloaded, chunkStatus.getChunkSizeMB());
}
chunkStatus.setCompleted(true);
chunkStatus.setEndTimeMs(System.currentTimeMillis());
System.out.println(chunkStatus.getChunkId() + " finished downloading.");
}
}
+18 -31
View File
@@ -34,48 +34,35 @@ 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.printf("Chunk: %d, Thread: %s\n",
chunk.getChunkId(), 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 workerThread : workerThreads){
workerThread.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 workerThread : workerThreads){
try {
workerThread.join();
} catch(InterruptedException e){
throw new RuntimeException(e);
}
}
// 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,
try {
monitorThread.join();
} catch(InterruptedException e){
throw new RuntimeException(e);
}
// 7. Print final report
System.out.println();
+7 -13
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;
@@ -55,8 +44,13 @@ public class ProgressMonitor implements Runnable {
);
// TODO:
// If all chunks are completed, print a final message and exit the loop
if(completedChunks == chunks.size()){
System.out.println("All chunks are completed. Downloaded file successfully.");
for(ChunkStatus chunk : chunks){
System.out.println(chunk);
}
break;
}
try {
Thread.sleep(monitorDelayMs);