Home » Core Java » Java Multithreading Tutorial

About Ima Miri

Ima Miri

Ima is a Senior Software Developer in enterprise application design and development. She is experienced in high traffic websites for e-commerce, media and financial services. She is interested in new technologies and innovation area along with technical writing. Her main focus is on web architecture, web technologies, java/j2ee, Open source and mobile development for android.

Java Multithreading Tutorial

Multithreading is the ability of a program to manage its use by more than one user and even to manage multiple requests by the same user. In the Java programming language, concurrent programming is mostly concerned with threads. However, processes are also important.

1. Process and Thread

A process is an execution of a program and a thread is a single execution of work within the process. A process can contain multiple threads. A thread is also known as a lightweight process.

process in java

In Java, a process is run independently from other processes in a JVM and threads in a JVM share the heap belonging to that process. That is why several threads may access the same object in the heap. Threads share the heap and have their own stack space. Therefore, an invocation of a method and its local variables are kept thread safe from other threads, while heap is not thread safe and must be synchronized for multithreaded programs.

2. Life cycle of a Thread

A thread can be in different states in its life cycle. The diagram below displays different states of a thread which are start, run, sleep/wait/block and done.

thread lifecycle

  • Runnable: A thread is waiting for its turn to be picked for execution. The thread is selected by the thread scheduler based on thread priorities.
  • Running: The processor is executing the thread. The thread runs until it becomes blocked or give up its turn with Thread.yield(). Due to overhead of context switching, yield() should not be used very frequently.
  • Waiting: A thread waits for another thread to perform a task.
  • Sleeping: Java threads are forced to sleep (suspended) with this overloaded method: Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds).
  • Blocked on I/O: A thread is blocked on some external I/O processing to finish. Thread will move to runnable after I/O condition like reading bytes of data etc changes.
  • Blocked on synchronization: Thread will move to Runnable when a lock is acquired.
  • Dead: The thread is finished its work.

3. How to implement a thread?

There are two ways to create a thread, 1) extends Thread class, 2) implements Runnable interface. Thread class itself implements the Runnable interface. Lets see how to define a single thread in java.

3.1. extends Thread class

When a class extends <code>Thread</code>, it should override the run() method and provide its own implementation of run(). The start() method in the <code>Thread</code> class starts the execution of a thread.

class SingleThread extends Thread{
    public void run(){
        System.out.println("Single Thread.");
    }
}

To run the SingleThread, the start() needs to be called. Then, JVM calls the run method of  this thread. The thread will be alive until the execution of the run method is finished.

public static void main(String[] args) {
    SingleThread thread = new SingleThread();
    thread.start();
}

3.2. implements Runnable

Similar to the previous implementation of a thread, when a class implements Runnable interface, it should provide its own implementation of run().

class RunnableThread implements Runnable{
    @Override
    public void run() {
        System.out.println("Runnable Thread.");
    }
}

Due to the Runnable doesn’t have start(), we create an instance of Thread class to start the thread and execute the run().

public static void main(String[] args) {
    Thread t = new Thread(new RunnableThread());
    t.start();
}

4. Multithreading

Lets have a look at some example to see how multithreading actually works in java. In the following example, there are three threads running. In the RunnableThread, sleep() is called to suspend the thread for a period of time. When t1 is suspended t2 is started. Also, t2 called join() to force the current thread to not execute until t2 is finished. Then, once t2 is finished, t3 will be executed.

class RunnableThread implements Runnable{@Override
   public void run() {
       try {
           System.out.println("Runnable Thread:"+Thread.currentThread().getName());
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           System.out.println(e.getMessage());
       }
   }
} 
public static void main(String[] args) {
   Thread t1 = new Thread(new RunnableThread());
   Thread t2 = new Thread(new RunnableThread());
   SingleThread t3 = new SingleThread();

   t1.start();
   t2.start();
   try {
       t2.join();
   } catch (InterruptedException e) {
       System.out.println(e.getMessage());
   }
   t3.start();
}

5. Thread priority in multithreading

Every thread has a priority that helps the program to determine the order which threads are scheduled. Thread priority is between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). Default priority of a thread is NORM_PRIORITY (a constant of 5).
Threads with higher priority are executed before threads with lower priority. However, thread priorities do not guarantee the order in which threads execute next and it is also platform dependent.

5.1. Thread priority example

Here is an example that how thread priority works in java.

class MultiThread extends Thread{
    public void run(){
        System.out.println("Running Thread Name: "+ this.currentThread().getName());
        System.out.println("Running Thread Priority: "+ this.currentThread().getPriority());
    }
}
public class MultiThreadingTutorial {
    public static void main(String[] args) {
        MultiThread multiThread1 = new MultiThread();
        multiThread1.setName("Thread1");
        multiThread1.setPriority(Thread.MIN_PRIORITY);

        MultiThread multiThread2 = new MultiThread();
        multiThread2.setName("Thread2");
        multiThread2.setPriority(Thread.MAX_PRIORITY);

        MultiThread multiThread3 = new MultiThread();
        multiThread3.setName("Thread3");

        multiThread1.start();
        multiThread2.start();
        multiThread3.start();
    }
}

And here is the output:

Running Thread Name: Thread1
Running Thread Name: Thread3
Running Thread Name: Thread2
Running Thread Priority: 10
Running Thread Priority: 5
Running Thread Priority: 1

6. Synchronization

Synchronization is about to control the access of threads on shared resources in the program. In Java, each object has a lock. A thread can acquire the lock for an object by using synchronized keyword. The synchronized keyword can be implemented in method level or block level. The block level is more efficient in comparison to method level because it does not lock the whole method.

The following example demonstrates how a synchronized method works.

class Output{

    public synchronized void print(String s){
        System.out.println(s);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }
    }
}

class Library extends Thread{
    Output output;

    public Library(Output output) {
        this.output = output;
    }

    public void run(){
        output.print("Library Print.");
    }
}

class University extends Thread{
    Output output;

    public University(Output output) {
        this.output = output;
    }

    public void run(){
        output.print("University Print.");
    }
}

public static void main(String[] args) {
    Output output = new Output();
    Library library = new Library(output);
    University university = new University(output);
    library.start();
    university.start();
}

Now, lets have a look at another example about synchronized block. I only added the scan() to the Output class as below.

public void scan(String s){
    synchronized (s){
        try {
             s.wait(1000);
             System.out.println("Scan is completed for "+s);
        } catch (InterruptedException e) {
             System.out.println(e.getMessage());
        }
    }
}

Sydnchronization is always important in multithreading programming, specially when we work with collections. In java, there are some collections that are thread safe such as Vector, Stack and HashTable. Java provides synchronized functionality to support thread safety on collections such as Collections.SynchronizedCollection() and Collections.SynchronizedMap().
Also, java.util.concurrent contains high-level utilities that are mainly used in concurrent programming.

7. Download the source code

This was a tutorial for Java multithreading tutorial.

Download
You can download the full source code of this example here: Java Multithreading Tutorial

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

 

Leave a Reply

1 Comment on "Java Multithreading Tutorial"

Notify of
avatar
Sort by:   newest | oldest | most voted
mayur kohli
Guest

Nice post!

After understanding the basics of Java multithreading, I recommend to check the Executors framework. Together with various built in classes, making complex multithreaded applications is simpler and cleaner than using Threads directly.

wpDiscuz