Implementation of HW-8 Multithreading is complete
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
# Advanced Programming Assignment 8
|
||||
|
||||
|
||||
* Name: *Hesam Ghazi*
|
||||
* Student Number: *403222015*
|
||||
* Course: *Advanced Programming*
|
||||
|
||||
---
|
||||
|
||||
# Theoretical Questions
|
||||
|
||||
## 1. `start()` vs `run()`
|
||||
|
||||
### Question 1: What output do you get from the program? Why?
|
||||
|
||||
The program prints something similar to the following:
|
||||
|
||||
```
|
||||
Calling run()
|
||||
Running in: main
|
||||
Calling start()
|
||||
Running in: Thread-2
|
||||
```
|
||||
|
||||
When `t1.run()` is called, the `run()` method executes like a normal Java method. It does **not** create a new thread, so it runs inside the current thread, which is the **main** thread.
|
||||
|
||||
When `t2.start()` is called, the Java Virtual Machine creates a **new thread**, and that thread executes the `run()` method independently. Therefore, `Thread.currentThread().getName()` returns `"Thread-2"`.
|
||||
|
||||
---
|
||||
|
||||
### Question 2: What's the difference in behavior between calling `start()` and `run()`?
|
||||
|
||||
| `start()` | `run()` |
|
||||
| -------------------------------------------------- | ------------------------------------------- |
|
||||
| Creates a new thread. | Does not create a new thread. |
|
||||
| Executes `run()` concurrently. | Executes `run()` like a normal method call. |
|
||||
| The JVM schedules the new thread. | Runs immediately in the current thread. |
|
||||
| Allows multiple threads to execute simultaneously. | No parallelism or concurrency occurs. |
|
||||
|
||||
For example:
|
||||
|
||||
```java
|
||||
Thread thread = new Thread(new MyRunnable());
|
||||
|
||||
thread.run(); // Executes on the current thread (main)
|
||||
thread.start(); // Executes on a new thread
|
||||
```
|
||||
|
||||
Using `start()` is essential when we want to perform tasks concurrently.
|
||||
|
||||
---
|
||||
|
||||
# 2. Daemon Threads
|
||||
|
||||
### Question 1: What output do you get from the program? Why?
|
||||
|
||||
A typical output is:
|
||||
|
||||
```
|
||||
Main thread ends.
|
||||
Daemon thread running...
|
||||
Daemon thread running...
|
||||
```
|
||||
|
||||
Sometimes only the following is printed:
|
||||
|
||||
```
|
||||
Main thread ends.
|
||||
```
|
||||
|
||||
This happens because daemon threads are **background threads**. When the main (user) thread finishes and no other user threads remain, the JVM automatically terminates all daemon threads, even if they have not completed their work.
|
||||
|
||||
Since the daemon thread sleeps for 500 ms in every iteration, it may be terminated before printing all twenty messages.
|
||||
|
||||
---
|
||||
|
||||
### Question 2: What happens if you remove `thread.setDaemon(true)`?
|
||||
|
||||
If `thread.setDaemon(true)` is removed, the thread becomes a **user thread**.
|
||||
|
||||
In this case, the JVM waits until the thread completes all twenty iterations before terminating the program.
|
||||
|
||||
The output becomes similar to:
|
||||
|
||||
```
|
||||
Main thread ends.
|
||||
Daemon thread running...
|
||||
Daemon thread running...
|
||||
...
|
||||
Daemon thread running...
|
||||
```
|
||||
|
||||
The program will continue running for approximately **10 seconds** (20 × 500 ms).
|
||||
|
||||
---
|
||||
|
||||
### Question 3: What are some real-life use cases of daemon threads?
|
||||
|
||||
Daemon threads are commonly used for background services that support the application but are not essential to its primary functionality.
|
||||
|
||||
Examples include:
|
||||
|
||||
* Garbage collection
|
||||
* Automatic cache cleanup
|
||||
* Logging services
|
||||
* Monitoring system resources
|
||||
* Background file synchronization
|
||||
* Session timeout checking
|
||||
* Periodic health checks
|
||||
* Scheduled maintenance tasks
|
||||
|
||||
These tasks should stop automatically when the application exits, making daemon threads an appropriate choice.
|
||||
|
||||
---
|
||||
|
||||
# 3. A Shorter Way to Create Threads
|
||||
|
||||
### Question 1: What output do you get from the program?
|
||||
|
||||
The program prints:
|
||||
|
||||
```
|
||||
Thread is running using a ...!
|
||||
```
|
||||
|
||||
This message is printed by the newly created thread after `thread.start()` is called.
|
||||
|
||||
---
|
||||
|
||||
### Question 2: What is the `() -> { ... }` syntax called?
|
||||
|
||||
The syntax
|
||||
|
||||
```java
|
||||
() -> {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
is called a **Lambda Expression**.
|
||||
|
||||
Lambda expressions were introduced in **Java 8** as a concise way to implement functional interfaces such as `Runnable`.
|
||||
|
||||
The previous code
|
||||
|
||||
```java
|
||||
Thread thread = new Thread(() -> {
|
||||
System.out.println("Thread is running using a ...!");
|
||||
});
|
||||
```
|
||||
|
||||
is equivalent to
|
||||
|
||||
```java
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Thread is running using a ...!");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Question 3: How is this code different from creating a class that extends `Thread` or implements `Runnable`?
|
||||
|
||||
There are three common approaches for creating a thread.
|
||||
|
||||
### 1. Extending `Thread`
|
||||
|
||||
```java
|
||||
class MyThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Running...");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Advantages**
|
||||
|
||||
* Easy for simple examples.
|
||||
|
||||
**Disadvantages**
|
||||
|
||||
* Java supports only single inheritance.
|
||||
* The task is tightly coupled with the thread.
|
||||
|
||||
---
|
||||
|
||||
### 2. Implementing `Runnable`
|
||||
|
||||
```java
|
||||
class MyRunnable implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Running...");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Advantages**
|
||||
|
||||
* Better object-oriented design.
|
||||
* Allows inheritance from another class.
|
||||
* The task and the thread are separated.
|
||||
|
||||
---
|
||||
|
||||
### 3. Using a Lambda Expression
|
||||
|
||||
```java
|
||||
Thread thread = new Thread(() -> {
|
||||
System.out.println("Running...");
|
||||
});
|
||||
```
|
||||
|
||||
**Advantages**
|
||||
|
||||
* Very concise and readable.
|
||||
* Eliminates unnecessary boilerplate code.
|
||||
* Ideal for short tasks.
|
||||
* Still implements the `Runnable` interface internally.
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Lambda expressions are the preferred choice for short and simple thread tasks because they produce cleaner and more maintainable code. For larger or reusable tasks, implementing `Runnable` is generally considered the best practice due to better separation of responsibilities. Extending `Thread` is the least flexible approach and is usually reserved for special cases.
|
||||
Reference in New Issue
Block a user