About NewTechnoBuzz
Advertise
Contact Us

Thursday, July 24, 2014

Different ways to implement Threads in Java

Java is a multithreaded programming language. A multithreaded program contains two or more threads that can run concurrently and can handle different task at the same time by making optimal use of available resources like CPU. Multithreading is also one of the popular topics in an interview for all fresher and experienced developers. The main problem for writing multithreaded program is related to concurrency like deadlock, race conditions etc. It takes lot of effort to write a multithreaded program in Java.

In this tutorial, I will share my experience on different way of implementing Threads in Java.

Different ways to implement Threads in Java:

Below are the different ways to implement threads in Java:
  • By implementing Runnable Interface
  • By extending Thread Class
  • By implementing Callable Interface (introduced in Java 5)

By Implementing Runnable Interface

If you want to implement multithreading in your program then you can achieve this by implementing Runnable interface.
class RunnableClass implements Runnable {

    public static int count = 0;
    public RunnableClass(){ }
        
    public void run() {
        while (RunnableClass.count <= 10) {
            try {
                System.out.println("Expl Thread: " + ( ++RunnableClass.count ));
                Thread.sleep(100);
            } 
            catch (InterruptedException ex) {
                System.out.println("Exception in Thread Class : " + ex.getMessage());
            }
        }
    } 
}
public class RunnableTest {
    public static void main(String args[]){
        System.out.println("Starting Main Thread...");
        RunnableClass thread = new RunnableClass();
        Thread t = new Thread(thread);
        t.start();
        while (RunnableClass.count <= 10) {
            try {
                System.out.println("Main Thread: "+( ++RunnableClass.count ));
                Thread.sleep(100);
            } 
            catch (InterruptedException ex){
                System.out.println("Exception in main thread: " + ex.getMessage());
            }
        }
        System.out.println("End of Main Thread...");
    }
}

Output:

Starting Main Thread...
Main Thread: 1
Expl Thread: 2
Main Thread: 3
Expl Thread: 4
Main Thread: 5
Expl Thread: 6
Main Thread: 7
Expl Thread: 8
Main Thread: 9
Expl Thread: 10
Main Thread: 11
End of Main Thread...

By extending Thread Class

class ThreadClass extends Thread {
    public static int count = 0;
    public void run() {
        while (ThreadClass.count <= 10) {
            try {
                System.out.println("Expl Thread: " + (++ThreadClass.count) );
                Thread.sleep(100);
            } 
            catch (InterruptedException ex) {
                System.out.println("Exception in thread: " + ex.getMessage());
            }
        }
    }
}
public class ThreadTest {
    public static void main(String args[]) {
        System.out.println("Starting Main Thread...");
        ThreadClass thread = new ThreadClass();
        thread.start();
        while (ThreadClass.count <= 10) {
            try {
                System.out.println("Main Thread: " + (++ThreadClass.count) );
                Thread.sleep(100);
            } 
            catch (InterruptedException ex) {
                System.out.println("Exception in main thread: " + ex.getMessage());
            }
        }
        System.out.println("End of Main Thread...");
    }
}

Output:

Starting Main Thread...
Main Thread: 1
Expl Thread: 2
Expl Thread: 3
Main Thread: 4
Expl Thread: 5
Main Thread: 5
Expl Thread: 6
Main Thread: 7
Main Thread: 8
Expl Thread: 9
Expl Thread: 11
Main Thread: 10
End of Main Thread...

By Implementing Callable Interface

Java 5 introduced java.util.concurrent.Callable interface in concurrency package that is similar to Runnable interface. But, it can return any Object and throw Exception. Callable interface use Generic to define the return type of Object. Executors class provide useful methods to execute Callable in a thread pool. Below is a simple example of Callable task:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableTest implements Callable<String> {

    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        //return the thread name
        return Thread.currentThread().getName();
    }
    
    public static void main(String args[]){
        //Get ExecutorService from Executors utility class, thread pool size is 10
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //create a list of Future object
        List<Future<String>> list = new ArrayList<Future<String>>();
  
        Callable<String> callable = new CallableTest();
        for (int i = 0; i < 100; i++){
            //submit Callable tasks to be executed by thread pool
            Future<String> future = executor.submit(callable);
            list.add(future);
        }

        for (Future<String> future : list){
            try {
                System.out.println("Name of Future Object : " + future.get());
            } 
            catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        //shut down the executor service
        executor.shutdown();
    }
}

Output:

Name of Future Object : pool-1-thread-1
Name of Future Object : pool-1-thread-2
Name of Future Object : pool-1-thread-3
Name of Future Object : pool-1-thread-4
Name of Future Object : pool-1-thread-5
Name of Future Object : pool-1-thread-6
Name of Future Object : pool-1-thread-7
Name of Future Object : pool-1-thread-8
Name of Future Object : pool-1-thread-9
Name of Future Object : pool-1-thread-10

Why implementing Runnable interface is better than extending Thread class

  • If your class extends the Thread class then it becomes a single thread which inherits the properties of Thread class, so it'll be heavy, while implementing Runnable, it shares the same object to multiple Threads.
  • Java allows single inheritance, which means that if you inherit from Thread you won't be able to inherit from any other class. Implementing the Runnable interface doesn't have this limitation.
So, extend Thread class only when you want to override the some behavior of Thread class.

Summary

  • Thread class limits the inheritance feature of class.
  • Extend Thread class only when you want to override some behavior of Thread class.
  • Runnable interface represent a Task which can be executed by either plain Thread or Executors. So logical separation of Task as Runnable is good design.
  • Inheriting all Thread methods are additional overhead just for representing a Task.
  • A Callable instance returns a type Future Object or throw an exception. So, use Callable interface when you to return any value or throw an exception because a Runnable instance can't return any value.
Please feel free to provide your comments, suggestions and feedback.

0 comments