Java Threads

So far you have been writing simple standalone applications that runs on the main thread. The main thread is the special thread created by JVM to execute your program by invoking the public static void main(String[] args) method. In any thread, the statements are executed one at a time in a sequence and no two statements can be executed in parallel in a single thread.

However, your application can create and start more threads which can execute blocks of program code in parallel with the main thread.

Some of the reasons why threads are created are:

  • In enterprise software systems, when multiple clients invoke your application, to handle every client a new thread is spawned on the server. This ensures that all the clients can execute their functionality in parallel instead of waiting on one another.
  • In client side programs, threads are spawned to handle long running/blocking operations (like uploading a picture to facebook; downloading a music file etc.) thereby the main thread is always waiting on the user and the worker thread does the blocking operation there by providing a great user experience to the user.

Creating Java Threads

There are two ways to create a thread in Java

  • By extending the Thread class.
  • By implementing the Runnable Interface

Let us take a look at both these methodologies

Extending the Thread Class

The Thread class is already in the Java API. Just extend the Thread class and override the run method of the parent. A new Thread is spawned when a new object is created of this class and the start() method is called. Here is an example


public class MyThread extends Thread {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        System.out.println("This code runs on the main thread and the name of this thread is - " + Thread.currentThread().getName());
    }

    public void run() {
        System.out.println("This code runs in a new thread and the name of this thread is - " + Thread.currentThread().getName());
    }
}

Notice that the run method is never called by the main program. The main program only calls the start method on the thread object. This will cause the JVM to spawn a new thread which executes the run() method. Thread.currentThread().getName() method returns the name of the thread that is executing that statement and you will notice that the names of the two are different. You can also check the Thread ID using the getId() method.

Implementing the Runnable Interface

You can also create a thread using the Runnable interface. In this method, you create a class that implements the Runnable interface. This will force you to implement the run method in this class. Next, you have to create a new Thread object and pass in an instance of the Runnable class and then call the start method on the thread. Here is an example:


public class MyRunnableClass implements Runnable {

    public static void main(String[] args) {
        MyRunnableClass obj = new MyRunnableClass();
        Thread thread = new Thread(obj);
        thread.start();
        System.out.println("This code runs in the main thread with reference - " + Thread.currentThread());
    }

    public void run() {
        System.out.println("This code runs in a new thead with reference - " + Thread.currentThread());
    }
}

Which way is better?

So the question is, which way of creating thread is better? Extending the Thread class or implementing the Runnable interface?

The answer lies in your functionality. The advantages of using Runnable interface is, you can use your existing class that may be inheriting from other classes and may also be implementing other interfaces but can still be converted to a Thread by implementing the Runnable interface. This flexibility of being any class is not there when you create a child of Thread. As Java only allows being a child of one parent only and not multiple parents, you are restricted to be anything else but a Thread class when your class is a child of Thread. That is not true when you implement the Runnable interface. Your class can be of any type.

Points to Note

Never call the run method directly. Invoke the start method to start a Thread and JVM will spawn a Thread which calls the run method underneath

Pausing (Sleeping) a Thread

A thread can be paused from executing and made to sleep for a while, by calling the static method Thread.sleep() . The sleep() takes a number of milliseconds to sleep as a parameter. The sleep() method will put the Thread to sleep that number of milliseconds before resuming execution. The timer is started by the underlying operating system and its timers and schedulers.

Here is an example of sleeping a Java thread for 5 seconds (5000 milli seconds) by calling the Thread sleep() method. Remember main thread is also a Thread:


package com.mbcc.tutorial.threads;

public class MyRunnableClass {

    public static void main(String[] args) {
        try {
            System.out.println("Going to sleep for 5 secs now. Don't disturb");
            Thread.sleep(5 * 1000);
            System.out.println("Woke up. Feel refreshed after sleeping for 5 secs!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Thread Concurrency (a.k.a Race Condition)

Since Threads run as per the OS scheduling, there is no way to know which thread is running at any point of time or what code block is being executing by which thread. A point to note is that regular variables are all shared by all the Threads. When the threads are reading and writing the same set of variables, the variable values at any point of time, could get unpredictable. This is called currency problem. Here is an example:


package com.mbcc.tutorial.threads;

public class MyThread extends Thread {

    static Product product = new Product();

    static int a[] = { 5, 7 };
    static int b[] = { 4, 10 };

    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.start();
        MyThread thread2 = new MyThread();
        thread2.start();
        System.out.println(product.a + "x" + product.b + "=" + product.getProduct() + " Main thread");

    }

    public void run() {

            product.a = a[product.counter];
            product.b = b[product.counter];
            product.counter++;
            System.out.println(product.a + "x" + product.b + "=" + product.getProduct() + "," + this.getId());

    }
}

class Product {

    int a;
    int b;
    int counter = 0;

    int getProduct() {
        return a * b;
    }
}

The above programs intention is to multiply elements in the same index position in array 'a' with that of array 'b'. Using threads to do this multiplication can get your results faster due to parallel computing, instead of using a single thread. The index positions are kept in a variable called 'counter' inside of the Product object. In this simple example we will use two threads and each thread will get one pair of multiplication to perform. So integers present at the same index position of both 'a' and 'b' are picked up and multiplied. I.e, 5x4 and 7x10 is what is required to be executed by two different threads. '0'th index in 'a' is multiplied with '0'th index in 'b' and '1'st index in 'a' is multiplied with '1'st index in 'b'.

When you run this code a few times, you will realize that the getProduct will use different index positions in array 'a' and 'b' and the results may not be what was expected. Some times it works just as expected but sometimes 5x10 or 7x4 is executed which is not the intended outcome. This is due to the concurrency issue that is going on. You do not know which thread is updating the different variables of the product at any given time and hence the mismatch.

Addressing Concurrency Problems

There are two ways to address concurrency issues in a Thread

  • Instead of using regular variable use ThreadLocal. This method is good when every Thread is allowed to keep its own copy of the variable.
  • Use synchronized keyword for the method or object. This technique is good when you have to have use the same variable that needs to be shared across all the threads. But you do not want to have unpredictable results due to that. All synchronized blocks can only have one thread executing inside them at any time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block completes the block. Here is an example

package com.mbcc.tutorial.threads;

public class MyThread extends Thread {

    public static Product product = new Product();

    int a[] = { 5, 7 };
    int b[] = { 4, 10 };

    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.start();
        MyThread thread2 = new MyThread();
        thread2.start();
        System.out.println(product.a + "x" + product.b + "=" + product.getProduct() + " Main thread");

    }

    public void run() {
        synchronized (product) {
            product.a = a[product.counter];
            product.b = b[product.counter];
            product.counter++;
            System.out.println(product.a + "x" + product.b + "=" + product.getProduct() + "," + this.getId());
        }
    }
}

class Product {

    int a;
    int b;
    int counter = 0;

    int getProduct() {
        return a * b;
    }
}

When you run this code multiple times, you will notice that the results are consistent and the same index number is used to get elements from 'a' and 'b' and that is what you intended to do.

results matching ""

    No results matching ""