Saturday, October 31, 2015

Multi threading (detailed)

What is Thread?
Multithreading refers to two or more tasks executing concurrently within a single program. A thread is an independent path of execution within a program. Many threads can run concurrently within a program. Every thread in Java is created and controlled by the java.lang.Thread class.
--cited from Java Threads Tutorial | Wideskills


This is the thread. Well, we can consider the thread as a robot which executes tasks within a program. We usually have only one main robot which executes tasks within a program (this robot is called "main thread"). But what if there is a tough task which takes a lot of time to execute...During the main robot executes the task, no robot can execute other tasks within a program. As a result, the program freezes during the main thread executes the tough task.

main robot is working.
image cited from: http://java2005.cis.k.hosei.ac.jp/materials/lecture26/multithreaded.html

Another robot was added.
image cited from: http://java2005.cis.k.hosei.ac.jp/materials/lecture26/multithreaded.html

How to use the multi threading

There are two ways to use the multi threading. One is to extends Thread class as following:

Extend Thread class

class Test {
    public static void main(String[] args) {
        SubTest tt = new SubTest();
        tt.start();
    }
}

class SubTest extends Thread {
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println( i + " Hello World");
        }
    }
}

SubTest class is extending Thread class. Then an object of SubTest class is created inside the main method of Test class. 

Once we execute the start method of Thread class, codes in-between the "run(){" and "}" are executed as follows:
result.

Implements Runnable interface

The another way is to implement runnable interface. See below for the code.

class Test {
    public static void main(String[] args) {
        SubTest tt = new SubTest();
        Thread t = new Thread(tt);
        t.start();
    }
}

class SubTest implements Runnable {
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println(i + " Hello World");
        }
    }
}

Result.

It is forbidden to extend multiple classes at once. Thus, if we want to use multi-threading though we are already extending one class, we must use this second way.

Synchronized

Please see the below program. This creates 10 threads and displays how many times the method was executed in this program.

---------------------------------
class Test {
    static Counter counter = new Counter();

    public static void main(String[] args) {

        // Create 10 threads
        MyThread[] threads = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new MyThread();
            threads[i].start();
        }

        // wait until all threads finish
        for (int i = 0; i < 10; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }

        // display the counter
        System.out.println(Test.counter.count);
    }
}

// thread
class MyThread extends Thread {
    public void run() {
        Test.counter.countUp(); //this indicates the countUp method below
    }
}

// counter
class Counter {
    int count;
    void countUp() {
        System.out.print("Hello, ");
        int n = count;            // the number n becomes the variable "count"
        System.out.print("World");
        count = n + 1;            // 1 is added to n. 
        //Every time this method is executed, the count's number increases by 1.
        System.out.println("!!");
    }
}
---------------------------------

Result 1: It displays 10.

Result 2: Sometimes it doesn't display 10. 

The result is shown above. But sometimes this doesn't display 10 which is the correct number. See Result 2 for the wrong result. In the Result 2, it displays 5. Why does this occur?

The Counter class has the reason why this is happening. We had 10 threads and some of the threads simultaneously executed the countUp method of Counter class, that is why, while one thread was executing countUp method, another thread simultaneously executed the countUp method. This resulted in the wrong result like Result 2 above.

This displays "Hello, WorldHello, World!!" which is missing another "!!" at the end.
Another "!!" shows up after 4 threads displays the "Hello, World!!", which means 1+4 threads cut in while one thread was exexcuting.

To avoid this "cutting-in-threads" problem, use "synchronized" statement as follows:
--------------------------------
void countUp() {
        synchronized (this) {
            System.out.print("Hello, ");
            int n = count;             // the number n becomes the variable "count"
            System.out.print("World");
            count = n + 1;            // 1 is added to n. 
            //Every time this method is executed, the count's number increases by 1.
            System.out.print("!!");
        }
    }
---------------------------------

The whole picture would be:

---------------------------------
class Test {
    static Counter counter = new Counter();

    public static void main(String[] args) {

        // Create 10 threads
        MyThread[] threads = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new MyThread();
            threads[i].start();
        }

        // wait until all threads finish
        for (int i = 0; i < 10; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }

        // display the counter
        System.out.println(Test.counter.count);
    }
}

// thread
class MyThread extends Thread {
    public void run() {
        Test.counter.countUp(); //this indicates the countUp method below
    }
}

// counter
class Counter {
    int count;
    void countUp() {
        synchronized (this) {
            System.out.print("Hello, ");
            int n = count;             // the number n becomes the variable "count"
            System.out.print("World");
            count = n + 1;            // 1 is added to n. 
            //Every time this method is executed, the count's number increases by 1.
            System.out.println("!!");
        }
    }
}
---------------------------------

Synchronized statement forbids the threads to execute the method simultaneously. That is why the threads don't get confused and are always displaying the correct result.

By the way, Synchronized statement can be written as follows also:
---------------------------------
class Global {
    static Object lock = new Object();
}

class Counter {
    void countUp() {
        synchronized (Global.lock) {
            // write your code here
        }
    }
}
---------------------------------