Tuesday 18 July 2017

Multi-Threading



Mutithreading, Parallel execution or Concurrency in other words is nothing but “spawning” (creating) multiple Threads and each Thread is carrying out the work that your application is meant to do. one Thread can only do one particular task at a time. This is a bottleneck if your entire application just runs on one Thread right?

Java multithreading allows you to do multiple tasks at the same time. This is possible because modern day computers have multiple CPUs. One CPU can work on one Thread at a time (unless your CPUs have hyper-threading, in which case it can handle two at a time). So this means that if your computer has 4 CPUs with hyper-threading technologies, your code could potentially handle 8 Threads at the same time.

Java Thread is a lightweight process that executes some task. Java provides multithreading support with the Thread class and an application can create multiple threads executing concurrently.


There are 2 types of Threads available in Java,

User threads: are threads which are created by the application or user. They are high priority threads. JVM (Java Virtual Machine) will not exit until all user threads finish their execution. JVM wait for these threads to finish their task. These threads are foreground threads.

Daemon threads: are threads which are mostly created by the JVM. These threads always run in background. These threads are used to perform some background tasks like garbage collection and house-keeping tasks. These threads are less priority threads. JVM will not wait for these threads to finish their execution. JVM will exit as soon as all user threads finish their execution. JVM doesn’t wait for daemon threads to finish their task.


When we start an application, main is the first user thread created and we can create multiple user threads as well as daemon threads. When all the user threads are executed, JVM terminates the program.

We can set different priorities to different Threads but it doesn’t guarantee that higher priority thread will execute first than lower priority thread. Thread scheduler is the part of Operating System implementation and when a Thread is started, it’s execution is controlled by Thread Scheduler and JVM doesn’t have any control on it’s execution.

There are 3 ways which you can create a Java Thread. Let's explore one by one.

By Extending Java Thread class:

import java.lang. * ;
public class WorkerThread extends Thread {
        @Override
 public void run() {....
 }
}

By Implementing Java Thread class:

import java.lang. * ;
public class WorkerThread implements Thread {
        @Override
 public void run() {....
 }
}

One liner statement to create new Thread:

Thread t = new Thread(new Runnable(){
    @Override
    public void run() {
    }
});

You can chose the right way of creating a thread based on your need. The only difference between the first two methods is that in second method you are implementing Runnable interface. So that it gives you a greater flexibility to your class WorkerThread to extend some other class. But this is not possible with first method as you cannot extend multiple classes.

Finally the 3rd method is one liner implementation means single time use only. It is not reusable as like first 2 methods. Go for the the 3rd method if it is only one time use.

Let's see some examples of creating threads and using them.

Creating thread with extending Thread class:

public class WorkerThread extends Thread {

  @Override
  public void run() {
    System.out.println("The user created thread Id is: " + Thread.currentThread().getId());
  }

  public static void main(final String[] args) {

    System.out.println("This is the main thread with Id:" + Thread.currentThread().getId());
    final WorkerThread thread = new WorkerThread();
    thread.start();
  }
}

Output:
This is the main thread with Id:1
The user created thread Id is: 11


Creating thread with implementing Runnable:


public class RunnableThread implements Runnable {

  @Override
  public void run() {
    System.out.println("The user created thread Id is: " + Thread.currentThread().getId());
  }

  public static void main(final String[] args) {

    System.out.println("This is the main thread with Id:" + Thread.currentThread().getId());
    final RunnableThread runnable = new RunnableThread();
    final Thread thread = new Thread(runnable);
    thread.start();
  }
}

Output:
This is the main thread with Id:1
The user created thread Id is: 11

If you observe above 2 methods of creating a thread is slightly different. In first method we created a class which extends a Java Thread class and we are creating and instance to out class and starting the thread with start() method which is used to start the thread. I will explain this later. But in 2nd method of implementation we are implementing Runnable interface with our own class and creating an instance for that class. But that is not enough here. We have to create an instance of a Thread class which takes our Runnable implementation class as a constructor argument. Then only you can start the thread.


In-line thread creation:

public class InLineThread {

  public static void main(final String[] args) {

    System.out.println("This is the main thread with Id:" + Thread.currentThread().getId());
    final Thread thread = new Thread(new Runnable() {

      @Override
      public void run() {
        System.out.println("The user created thread Id is: " + Thread.currentThread().getId());
      }
    });
    thread.start();
  }
}

Output:
This is the main thread with Id:1
The user created thread Id is: 11

You can create inline threads anywhere inside a method. Above is a one liner statement to create new Thread, Here we are implementing Runnable as an Anonymous Class. This implementation is not reusable.

Note: If you want reusable threads to use multiple times anywhere in your application prefer first 2 ways of creating a thread.

Now, we know how to create a Thread in Java. Let's see some important things to know about threads.


Pausing Execution with Sleep:

Thread.sleep is a method from Thread class which takes milliseconds as an argument causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system. This method always throw InterruptedException. You can either throw it or catch it. 

import java.util.Date;

public class ThreadsDemo {

  public static void main(final String[] args) throws InterruptedException {

    System.out.println("Started execution at : " + new Date());
    // sleep for 2 seconds
    Thread.sleep(2000);
    System.out.println("Finished execution at : " + new Date());
  }
}

Output:
Started execution at : Mon Jul 17 12:20:40 BST 2017
Finished execution at : Mon Jul 17 12:20:42 BST 2017


Starting a Thread:

start() method is responsible for starting a thread. Even though the thread is created, it is not executed until you explicitly invoke it by start method except main thread. Please refer above examples.


Stopping a thread:

There was a stop() method in Thread class, when Java was first released but that was deprecated later.Thread termination is not so straight forward. A running thread, may own files and sockets. It may hold locks. Abrupt Termination is not always easy: Unpredictable consequences may arise if the thread is in the middle of writing to a file and is killed before it can finish writing. Or what about the monitor locks held by the thread when it is shot in the head?

But we can create our own stop method which is very simple. There are many ways that you can stop a thread but all of them take specific code to do so. A typical way to stop a thread is to have a volatile boolean field that the thread checks every so often:


public class Server implements Runnable {

  private volatile boolean stop;

  public static void main(final String[] args) throws InterruptedException {

    final Server server = new Server();
    final Thread thread = new Thread(server);
    // Start the server thread
    thread.start();
    // Keep server started for 5 seconds
    Thread.sleep(5000);
    // Stop the server
    server.stop();
  }

  @Override
  public void run() {
    System.out.println("Starting server");
    // This checks if the thread has to be stopped
    while (!stop) {
      System.out.println("Server is running");
      try {
        // Sleep for a second every time before checking to stop
        Thread.sleep(1000);
      } catch (final InterruptedException e) {
      }
    }
    System.out.println("Server stopped");
  }

  // Method to stop the server thread
  public void stop() {
    this.stop = true;
  }

}

Output:
Starting server
Server is running
Server is running
Server is running
Server is running
Server is running
Server stopped

In above example, we are starting the server and keeping it alive for 5 seconds and then stopping it. Server is running in a separate thread than main thread and we are controlling server thread from main thread. Means you can increase server life by increase the sleep time in the main thread and stop wherever needed after completing necessary work with server..

2 comments: