Intro to Writing Multithreading in Java
Tags: java
Published: 2023-01-16 08:31:09

Multithreading is like creating a new branch that runs independently and uses common resources (different from multiprocessing, which creates new memory address for each process). 

There are mainly two approaches for writing multithreading in Java. In this tutorial, we are going to demonstrate it by writing classes that counts from 0 to 2. Each sleeping 1 second. The interesting part is, we want to run many threads that doing the exactly the same thing. 


## Extends Thread class 
```java
public class MultithreadingThingByExtendingThreadClass extends Thread {
    private int threadNumber;

    public MultithreadingThingByExtendingThreadClass(int threadNumber) {
        this.threadNumber = threadNumber;
    }

    @Override
    public void run() {
        for (int i=0; i<3; i++) {
            System.out.println(i + " from thread (ExtendingThreadClass) " + threadNumber);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // do nothing
            }
        }
    }
}
```

In test driver: 

```java
public class TestDriver {
    public static void main(String[] args) {
        System.out.println("Testing MultithreadingThingByExtendingThreadClass");
        for (int i=0; i<5; i++) {
            MultithreadingThingByExtendingThreadClass m =
                    new MultithreadingThingByExtendingThreadClass(i);
            m.start();
        }

    }
}
```

Here, `m.start()` will start a new thread. The output will be something like this: 
```
Testing MultithreadingThingByExtendingThreadClass
0 from thread (ExtendingThreadClass) 4
0 from thread (ExtendingThreadClass) 2
0 from thread (ExtendingThreadClass) 1
0 from thread (ExtendingThreadClass) 0
0 from thread (ExtendingThreadClass) 3
1 from thread (ExtendingThreadClass) 4
1 from thread (ExtendingThreadClass) 1
1 from thread (ExtendingThreadClass) 2
1 from thread (ExtendingThreadClass) 3
1 from thread (ExtendingThreadClass) 0
2 from thread (ExtendingThreadClass) 1
2 from thread (ExtendingThreadClass) 3
2 from thread (ExtendingThreadClass) 0
2 from thread (ExtendingThreadClass) 4
2 from thread (ExtendingThreadClass) 2
```

We observe the order of running threads is not the order of creation of threads. 

Note here if we use `m.run()` instead of `m.start()`, we will finish current thread first, after which we begin a new thread. That breaks the point of multithreading, isn't it? 

To see this, change `m.start()` to `m.run()`

```java
public class TestDriver {
    public static void main(String[] args) {
        System.out.println("Testing MultithreadingThingByExtendingThreadClass");
        for (int i=0; i<5; i++) {
            MultithreadingThingByExtendingThreadClass m =
                    new MultithreadingThingByExtendingThreadClass(i);
            m.run();
        }

    }
}
```
This is what we get: 

```
Testing MultithreadingThingByExtendingThreadClass
0 from thread (ExtendingThreadClass) 0
1 from thread (ExtendingThreadClass) 0
2 from thread (ExtendingThreadClass) 0
0 from thread (ExtendingThreadClass) 1
1 from thread (ExtendingThreadClass) 1
2 from thread (ExtendingThreadClass) 1
0 from thread (ExtendingThreadClass) 2
1 from thread (ExtendingThreadClass) 2
2 from thread (ExtendingThreadClass) 2
0 from thread (ExtendingThreadClass) 3
1 from thread (ExtendingThreadClass) 3
2 from thread (ExtendingThreadClass) 3
0 from thread (ExtendingThreadClass) 4
1 from thread (ExtendingThreadClass) 4
2 from thread (ExtendingThreadClass) 4
```

We can see how threads are executed _sequentially_ instead of _parallelly_.

One worth mention drawback of this approach is that Java doesn't allow multi-inheritance, so we cannot extend other classes. 

To remedy this, another approach is implementing Runnable interface, as Java does allow implementing many interfaces. 

## Implementing the Runnable Interface

```java
public class MultithreadingThingByImplementingRunnableInterface
implements Runnable
{

    private int threadNumber;

    public MultithreadingThingByImplementingRunnableInterface(int threadNumber) {
        this.threadNumber = threadNumber;
    }

    @Override
    public void run() {
        for (int i=0; i<3; i++) {
            System.out.println(i + " from thread (ImplementingRunnableInterface) " + threadNumber);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // do nothing
            }
        }
    }
}
```

However, when we write testdriver, we do it a bit differently. We need to create a thread ourselves, and wrap the stuff inside: 

```java
public class TestDriver {
    public static void main(String[] args) {

        System.out.println("Testing MultithreadingThingByImplementingRunnableInterface");
        for (int i=0; i<5; i++) {
            MultithreadingThingByImplementingRunnableInterface m =
                    new MultithreadingThingByImplementingRunnableInterface(i);
            Thread myThread = new Thread(m);
            myThread.start();
        }

    }
}
```
We get just the same output: 
```
Testing MultithreadingThingByImplementingRunnableInterface
0 from thread (ImplementingRunnableInterface) 2
0 from thread (ImplementingRunnableInterface) 3
0 from thread (ImplementingRunnableInterface) 4
0 from thread (ImplementingRunnableInterface) 0
0 from thread (ImplementingRunnableInterface) 1
1 from thread (ImplementingRunnableInterface) 0
1 from thread (ImplementingRunnableInterface) 2
1 from thread (ImplementingRunnableInterface) 4
1 from thread (ImplementingRunnableInterface) 3
1 from thread (ImplementingRunnableInterface) 1
2 from thread (ImplementingRunnableInterface) 0
2 from thread (ImplementingRunnableInterface) 4
2 from thread (ImplementingRunnableInterface) 2
2 from thread (ImplementingRunnableInterface) 3
2 from thread (ImplementingRunnableInterface) 1
```


## Reference 

[Coding with John](https://www.youtube.com/watch?v=r_MbozD32eo)