# 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.