Tuesday, March 19, 2024

MULTI-THREADING IN JAVA

Threads in Java:-


Threads are the smallest unit of execution within a process in a multitasking operating system. A thread refers to an independent path of execution within a program. Threads allow concurrent execution of multiple tasks, enabling programs to perform multiple operations simultaneously.

 

Facts about Threads:-

Ø Each thread has its own call stack, program counter, and set of registers, allowing it to execute independently of other threads within the same process.

Ø Threads share the same memory space, allowing them to access and modify shared data.

Ø Threads are commonly used in software development to improve performance, responsiveness, and resource utilization.

Ø In Java, threads are represented by instances of the Thread class or by implementing the Runnable interface.

Ø Threads can be created, started, paused, resumed, and terminated within a Java program, allowing developers to use concurrent programming to achieve their goals.

   What is Multi-threading ?

Multithreading in a feature in java which allows multiple threads to execute concurrently within a single Java program. This concurrent execution can lead to improved performance and responsiveness, especially in applications that involve tasks that can be executed independently. It enables developers to write concurrent programs that can perform multiple tasks simultaneously.

 

Life cycle of a thread:-

Life cycle of a thread consists of various stages through which a thread passes, from it’s creation to it’s termination.

It is depicted in the below figure.




Implementation of threads in java :-

 

Thread Class and Runnable Interface: In Java, multithreading is achieved by creating instances of the Thread class or implementing the Runnable interface. Both approaches involve defining the code that each thread will execute.

Creating Threads: You can create a thread by extending a subclass that is Thread class and overriding its run() method to specify the task to be performed by the thread. Alternatively, you can implement the Runnable interface and provide the task code in the run() method of the Runnable object.

Starting Threads: Once a thread is created, it can be started by calling its start() method. This initiates the execution of the thread, causing the run() method to be invoked in a separate call stack.

Thread States: Threads in Java can be in different states such as NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, or TERMINATED. These states represent the various stages of a thread's lifecycle.

Thread Synchronization: When multiple threads access shared resources concurrently, thread synchronization mechanisms like synchronized blocks and methods are used to ensure data consistency and prevent race conditions.

Thread Communication: Threads can communicate with each other through methods such as wait(), notify(), and notifyAll(). These methods allow threads to coordinate their activities and share data safely.

Thread Pools: Java provides utilities like ExecutorService and ThreadPoolExecutor for managing pools of threads, which can improve performance by reusing threads rather than creating new ones for each task.


Various thread functions :-

 start(): This method is used to start the execution of a thread. Once started, the thread moves from the new state to the runnable state, and eventually to the running state when it gets CPU time.

 

run(): The run() method contains the code that defines the behavior of the thread. It is invoked when the start() method is called and executes within the context of the thread.

 

sleep(long milliseconds): The sleep() method pauses the execution of the current thread for the specified number of milliseconds. It is often used to introduce delays in thread execution.

 

join(): The join() method allows one thread to wait for the completion of another thread. When a thread calls join() on another thread, it waits until that thread terminates before continuing its own execution.

 

interrupt(): The interrupt() method is used to interrupt the execution of a thread. When called, it sets the interrupt status of the thread, causing it to throw an Interrupted Exception if it is in a blocking state such as sleep() or wait().

 

 wait(): Using this method, the thread remains in the waiting state until another thread calls notify() or notifyAll() on the same object or until it is interrupted.

 

notify(): The notify() method wakes up a single thread that is waiting on the same object. If multiple threads are waiting on the object, the scheduler chooses one of them to be awakened.

 

notifyAll(): This method is typically used when multiple threads are waiting for a particular condition to be satisfied, and notifying all of them is necessary to ensure that no thread remains stuck in the waiting state.

 

Example displaying multi-threading:-

 

public class Recipeapp extends Thread {

    String description;

    int duration;

    Recipeapp(String description, int duration){

        this.description=description;

        this.duration=duration;

    }

    @Override

    public void run(){

        try{

            System.out.println(description);

            Thread.sleep(duration);

        }

        catch(InterruptedException e){

            e.printStackTrace();

        }

    }

}

public class Main {

    public static void main(String[] args) {

       Recipeapp onion = new Recipeapp("chop the onions", 2000);

       Recipeapp tomato = new Recipeapp("chop the tomatoes", 2000);

        Recipeapp pan = new Recipeapp("heat the pan", 2000);

        Recipeapp water = new Recipeapp("boil the water", 8000);

        Recipeapp pasta = new Recipeapp("put the pasta", 4000);

        //here we are studying the join function of the thread

        try {

            onion.start();

            onion.join();

            tomato.start();

            tomato.join();

            pan.start();

            pan.join();

            water.start();

            water.join();

            pasta.start();

            pasta.join();

        }

        catch(InterruptedException e){

            e.printStackTrace();

        }     

}

}     

 

Where to use multi-threading ?

1.    Database heavy applications (when you are searching in a huge database)

2.    When there is dependency on other services (when you are sending request to other servers)

3.    Multiple tasks operating simultaneously (Like in a video game, multimedia applications, operating systems)

Where not to use multi-threading ?

1.    When the steps are dependent on each other (as you cannot run the tasks in background)

2.    For the small tasks (the short tasks that do not take much time)

3.    For the simple tasks (where its pointless to add more complexity)

No comments:

Post a Comment