Files
HW-08-Basic-Multithreading/Report.md
T
2026-06-08 11:54:00 +03:30

4.2 KiB
Raw Blame History

Theoretical Questions 📝

1. start() vs run()

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();    
    }  
}  

What output do you get from the program? Why?

Answer:

The program first prints:

Calling run()
Running in: main

then it waits for 100ms (Thread.sleep(100);)
then it prints:

Calling start()
Running in: Thread-2

When t1.run() is called, it does not create a new thread. It just executes the run() method like a normal method inside the main thread. That is why the thread name is main.

When t2.start() is called, Java creates a new separate thread, and then that new thread executes the run() method. That is why the thread name is Thread-2.

Whats the difference in behavior between calling start() and run()?

Answer:

Calling run() directly only runs the code in the current thread, like a normal method call.

Calling start() creates a new thread and then runs the run() method inside that new thread. So start() enables true multithreading, but run() does not.


2. Daemon Threads

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.");    
    }  
}  

What output do you get from the program? Why?

Answer:

The output will usually be:

Main thread ends.

The daemon thread may print "Daemon thread running..." zero or a few times, but it is not guaranteed to finish. This happens because daemon threads do not keep the JVM alive. When the main thread ends and there are no user threads left, the JVM can terminate immediately.

What happens if you remove thread.setDaemon(true)?

Answer:

If thread.setDaemon(true) is removed, the thread becomes a normal user thread.

In that case, the JVM will wait for it to finish. So the program will keep running until the loop finishes, and "Daemon thread running..." will be printed 20 times.

What are some real-life use cases of daemon threads?

Answer:

Daemon threads are useful for background tasks that should not prevent the program from exiting.

Some examples are garbage collection, background monitoring, auto-saving, logging services, cache cleanup, and background resource management.


3. A shorter way to create threads

public class ThreadDemo {  
    public static void main(String[] args) {  
        Thread thread = new Thread(() -> {  
            System.out.println("Thread is running using a ...!");  
        });  
  
        thread.start();  
    }  
}   

What output do you get from the program?

Answer:

The output is: Thread is running using a ...!

What is the () -> { ... } syntax called?

Answer:

The () -> { ... } syntax is called a lambda expression.

How is this code different from creating a class that extends Thread or implements Runnable?

Answer:

This code uses a lambda expression to provide the implementation of the Runnable interface directly.

It is shorter and cleaner than creating a separate class that extends Thread or implements Runnable. It is useful when the thread task is simple and only needed once.