Multi threading
Tags: java
Published: 2022-09-04 17:13:17

## What are threads? 

a thread is a part of a [process](https://en.wikipedia.org/wiki/Process_(computing)) under execution. When we run a java program, we often just run the process of [JVM](https://en.wikipedia.org/wiki/Java_virtual_machine). JVM triggers the the 'main' thread of the program under execution for us and creates a [call stack](https://en.wikipedia.org/wiki/Call_stack) beginning with main().

We can have multiple threads doing different things in, what appears to be the same time.

## Why would I use multiple threads?

using multiple threads enable us to perform multiple tasks within the same application. For example, 

- While using an application like a text editor, a thread caters to editing tasks, another can maintain cache, another can run spell check etc. 
- On a server, we can have multiple threads catering to multiple clients
- While playing games, we can have dedicated threads for user control while other threads can implement game logic
- We can have multiple threads doing numerous asynchronous tasks for any application

## How to Use Multiple Threads? 

There are two ways of implementing multi threading:

1. Implement Runnable Interface
2. Extend Thread Class

The Runnable Interface and the Thread class are provided in the, [java.langs](https://docs.oracle.com/javase/7/docs/api/java/lang/package-summary.html) package, therefore, are implicitly accessible in all java programs.

For understanding the implementation of multi threading. Lets take an example of teaching at a school. Bob is a teacher, he teaches. Sally is a worker, she works. 

![Implementing Runnable vs extending Thread](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35s8wnpnpwc8w5n5qsa6.png)

Bob is a specialized worker (a teacher), whereas Sally is a generalized worker who needs a job.

In order to make a bob thread, we first need to define a teacher

```
class Teacher extends Thread
{
    @Override
    public void run()
    {
        System.out.println("teach teach 👨‍🏫");
    }
}
```
the Thread class (with a capital T) defines a worker, a thread is an instance of the Thread class which is a worker. Instead of defining the teacher, we can also define the job of teaching

```
class Teach implements Runnable
{
    @Override
    public void run() {
        System.out.println("teach teach 👨‍🏫");
    }
}
```
Here we implement the Runnable interface. In both cases, we must override the method run(). run() contains the set of instructions for getting the job done. 

And finally we can get Bob and Sally to work

```
public class School
{
    public static void main(String[] args) {
        Teacher bob=new Teacher();
        bob.start();
        Thread sally=new Thread(new Teach());
        sally.start();
    }
}
```

we instantiate the teacher bob and the call the method start(), this creates a separate call stack that starts with run() defined in the class Teacher. Similarly, we instantiate the thread sally, and pass an instance of the job Teach in its constructor. On calling start(), another call stack beginning with the run() defined in class Teach is created. 

_When we use the Runnable interface, we essentially define a job and then assign it to a thread. Whereas, when we extend the Thread class, we are defining a worker._

**When to use either?**

Apart from the conceptual difference, there's also a practical difference between the two. After extending class Thread, class Teacher cannot extend any other classes, whereas class Teach can still extend other classes.

_So if you wish to extend other classes, you must implement the Runnable interface._

Now we have 3 call stack, a main, one crated by bob, and one created by sally. All working at the apparent same time. 

## Apparent, huh? 

Even though we are using multiple threads, They are all part of the same process, the JVM. Even though your PC might have multiple processor, the JVM must run on only one of them. Therefore, all threads have access to that same processor. Even though it looks like the JVM allows multiple threads to execute concurrently, _in reality all threads take turns using the processor._ 

Allocation of computing resources is done by java's thread scheduler. It is some sort of a gate keeper who gets to decide which thread will get to use which resources, and for how long.

![Thread Scheduler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gfqj8wfhs3i5zko1cr1.png) 

The thread scheduler works at will, and there's no way for us to control or predict how it should schedule the threads. Although we can influence its decision, but we cannot know for certain when will it schedule a thread for execution. It may even [preempt](https://en.wikipedia.org/wiki/Preemption_(computing)) certain threads from completing and let other threads execute first. Or it may [starve](https://www.educative.io/answers/what-is-a-starvation-problem-in-an-operating-system) other threads.

## How do multiple threads run? 

Threads exist in 3 different states. Runnable (ready), Running, and Asleep. 

![3 states of threads](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8evlh0wtg6g3jjl74f8.png)

In the above example, `Teacher bob=new Teacher();` and `Thread sally=new Thread(new Teach());` creates 2 new thread objects. `bob.start();` and `sally.start();` bring them in ready state. Then its upto the Thread Scheduler to pick them and let them execute their jobs, or interrupt them and put them to sleep. Ultimately, they will finish their tasks as their call stacks fall out of existence.  

We can time an interrupt using the sleep() method. It guarantees that for the specified period of time, the thread shall not execute. Let's redefine the teacher's job to teach 5 lectures in a day. 

```
class Teacher extends Thread {
    public void teach() {
        System.out.println(this.getName()+" teach");
    }

    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            teach();
        }
    }
}
```
Now lets instantiate bob and sally and run the program. 

```
public class School
{
    public static void main(String[] args) {
        Teacher bob=new Teacher();
        bob.setName("Bob");
        Teacher sally=new Teacher();
        sally.setName("Sally");

        bob.start();
        sally.start();
    }
}
```
here are the results from 3 runs I made: 

![experiment 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/okz10xowlah0vtn1ytvu.png)

you can see preemption in the first 2 cases. However, in the third case, Sally was made to wait until Bob finishes.

Lets make an explicit interrupt and make Sally and Bob take a 5 sec (or 5000 milliseconds) nap after every lecture. 

```
class Teacher extends Thread {
    public void teach() {
        System.out.println(this.getName()+" teach");
    }

    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            teach();
            try {
                sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
```
sleep() throws InterruptedException, although its unlikely to be interrupted. However, the exception must be handled. 

results from the run: 

![experiment 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72sxybm8qcdw3cbt8zlc.png)

here Bob and Sally did go to sleep after every lecture. In Run 3, we can see Sally going to sleep, waking up and even teaching again even before Bob got the chance to teach. 

## Further Reading

Now multi threading seems great. We can use it for anything and everything. Right? githR?
![problem](https://i.imgur.com/RbelQBq.png)