# Multithreading

Multithreading in Java allows you to execute multiple threads (smaller units of a process) concurrently, which can help improve the performance and responsiveness of your Java applications. Java provides built-in support for multithreading through the `java.lang.Thread` class and the `java.lang.Runnable` interface. Here are the basic concepts and steps involved in working with multithreading in Java:

**Creating Threads**:

You can create a thread by extending the `Thread` class or implementing the `Runnable` interface. Implementing `Runnable` is often preferred because it allows you to separate the task (runnable object) from the threading mechanism.

Example of extending `Thread`:

```java
class MyThread extends Thread {
    public void run() {
        // Code to be executed in this thread
    }
}
```

Example of implementing `Runnable`:

```java
class MyRunnable implements Runnable {
    public void run() {
        // Code to be executed in this thread
    }
}
```

**Creating Thread Objects**:

To start a thread, you need to create a `Thread` object and pass an instance of your class that extends `Thread` or implements `Runnable` to its constructor.

```java
MyThread myThread = new MyThread();
Thread thread = new Thread(new MyRunnable());
```

**Starting Threads**:

To start a thread, call the `start()` method on the `Thread` object. This method internally calls the `run()` method defined in your class.

```java
myThread.start();
thread.start();
```

**Thread Synchronization**:

When multiple threads access shared resources, you may encounter race conditions. Java provides synchronization mechanisms like `synchronized` blocks/methods and the `java.util.concurrent` package to manage thread synchronization and avoid data corruption.

```java
synchronized void synchronizedMethod() {
    // Synchronized code block
}
```

**Thread States**:

Threads can be in various states like NEW, RUNNABLE, BLOCKED, WAITING, TIMED\_WAITING, and TERMINATED. Understanding these states can help in debugging and managing threads effectively.

<figure><img src="https://media.geeksforgeeks.org/wp-content/uploads/20230620182419/Lifecycle-and-States-of-a-Thread-in-Java-768.png" alt=""><figcaption><p>Lifecycle of a thread</p></figcaption></figure>

**Thread Sleep**

The `sleep()` method pauses the execution of a thread for a specified amount of time.

```java
javaCopy codeThread thread = new Thread(() -> {
    for (int i = 1; i <= 5; i++) {
        System.out.println("Thread: " + i);
        try {
            Thread.sleep(1000); // Sleep for 1 second
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});

thread.start();
```

**Thread Joining**:

You can use the `join()` method to wait for a thread to finish its execution before continuing with the current thread.

```java
Thread thread1 = new Thread(() -> {
    for (int i = 1; i <= 5; i++) {
        System.out.println("Thread 1: " + i);
    }
});

Thread thread2 = new Thread(() -> {
    for (int i = 1; i <= 5; i++) {
        System.out.println("Thread 2: " + i);
    }
});

thread1.start();
thread2.start();

try {
    thread1.join(); // Wait for thread1 to finish
    thread2.join(); // Wait for thread2 to finish
} catch (InterruptedException e) {
    e.printStackTrace();
}

System.out.println("Main thread is done.");
```

**Thread Priorities**:

Threads can have different priorities (1-10), and you can set their priority using the `setPriority()` method. Higher-priority threads get more CPU time, but it's not always guaranteed, as it depends on the underlying OS.

<figure><img src="https://howtodoinjava.com/wp-content/uploads/2022/08/thread.png" alt=""><figcaption><p>Thread priorities</p></figcaption></figure>

**Daemon Threads**:

Threads can be marked as daemon threads, which will terminate when all non-daemon threads finish their execution. You can set a thread as a daemon using `setDaemon(true)`.

```java
thread.setDaemon(true);
```

This example demonstrates the some built-in methods of the `Thread` class:

```java
javaCopy codepublic class ThreadMethodsExample {
    public static void main(String[] args) throws InterruptedException {
        // Create a new thread
        Thread thread = new Thread(() -> {
            System.out.println("Thread started.");

            try {
                // Sleep for 2 seconds
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted while sleeping.");
                return; // Exit the thread
            }

            System.out.println("Thread resumed after sleep.");

            // Check if the thread is interrupted
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is interrupted.");
            } else {
                System.out.println("Thread is not interrupted.");
            }
        });

        // Start the thread
        thread.start();

        // Wait for the thread to finish
        thread.join();

        // Check if the thread is alive
        if (thread.isAlive()) {
            System.out.println("Thread is still alive.");
        } else {
            System.out.println("Thread has finished.");
        }

        // Interrupt the thread
        thread.interrupt();

        // Check if the thread is interrupted
        if (thread.isInterrupted()) {
            System.out.println("Thread is interrupted after interruption.");
        } else {
            System.out.println("Thread is not interrupted after interruption.");
        }
    }
}
```

* `start()`: Starts the execution of the thread.
* `join()`: Waits for the thread to finish executing.
* `getName()`: Returns the name of the thread.
* `getPriority()`: Returns the priority of the thread.
* `getState()`: Returns the state of the thread.
* `sleep()`: Causes the thread to sleep for a specified number of milliseconds.
* `yield()`: Causes the thread to voluntarily give up the CPU to other threads.
* `interrupt()`: Interrupts the thread.
* `isInterrupted()`: Checks if the thread has been interrupted.
* `isAlive()`: Checks if the thread is still alive.

These methods can be used to control the behavior of threads in your Java applications.

Multithreading in Java can significantly enhance the performance and responsiveness of your applications, but it also introduces challenges related to synchronization and coordination between threads. Careful design and proper synchronization are essential for writing robust multithreaded code.
