By Shubham Aggarwal | 1/19/2017 | General |Intermediate

Threading and Synchronization in Java

Threading and Synchronization in Java

In this tutorial, we will study the concept of threads in Java. From what they are, how to classify them, break them and use them will be the main focus of this guide. Here is what we will be looking at overall in this tutorial :

 

  • What is a Thread.
  • Difference between a process, a task and a thread.
  • Lifecycle of a thread.
  • Multithreading in Java.
  • States a thread can hold.
  • Thread priorities.
  • Thread class and Runnable interface.
  • Synchronised block.

 

Multithreading was designed into Java from the very beginning. You'll see support for multithreading in special keywords and in a number of classes in the Java Standard API. Understanding threading is a very important part of being an accomplished Java developer.

 

Let’s dive into threads and how they handle so much!

What is a Thread?

Any program in execution is called a process. A thread is termed as a lightweight process.

 

>>> A process can consist of multiple threads.

 

A thread has its own:

  • Program counter which keeps track of which instructions to execute next.
  • System registers which hold its current working variables.
  • A stack which contains the execution history.

 

Threads can share data with other threads like open files, state and code segment.

Properties of Threads

Let’s discuss some thread properties and characteristics:

 

  • A thread is also called a lightweight process.
  • Each thread belongs to exactly one process.
  • No thread can exist outside a process.
  • In Java, every thread in the JVM is represented by a Java object of class Thread.
  • A thread in Java can have some states like New, Runnable, Blocked, Waiting, Terminated.

Process vs Threads

 

Process

Thread

Process is heavy weight.

Thread is light weight, taking lesser resources than a process.

If one process is blocked, then no other process can execute until the first process is unblocked.

While one thread is blocked and waiting, a second thread in the same task can run.

Process switching needs interaction with operating system.

Thread switching does not need interaction with OS.

Multiple processes without using threads use more resources.

Multiple threaded processes use fewer resources.

In multiple processes each process operates independently of the others.

One thread can read, write or change another thread's data.

 

The above table shows enough and basic differences between a process and threads.

Threads in Java

Even if you don't create any thread explicitly in your program, a thread called main thread is still created. Although the main thread is automatically created, you can control it by obtaining a reference to it by calling currentThread() method.

 

Two important things to know about main thread are,

  • It is the thread from which other threads will be produced.
  • main thread must always be the last thread to finish execution.

 

 

class MainThread {

public static void main(String[] args) {

 Thread t = Thread.currentThread();

 t.setName("MyMainThread");

 System.out.print("DiscoverSDK, Thread name is " + t);

}

}

Output of the above program is very much easy to interpret:

 

DiscoverSDK, Thread name is [MainThread,5,main]

 

To create another thread in Java, there are two ways:

  • Extend Thread class.
  • Implements Runnable interface.

 

Let’s discuss these methods in their own section and discuss what way is recommended.

extends Thread class

Thread class is the main class on which Java's Multithreading system is based upon.

Thread class have some constructors which have different functionalities. Four constructors are:

  1. Thread ( )
  2. Thread ( String str ) - This method creates
  3. Thread ( Runnable r )
  4. Thread ( Runnable r, String str)

 

Thread class also defines many methods for managing threads. Some of them are:

 

Method

Description

setName()

to give thread a name

getName()

return thread's name

getPriority()

return thread's priority

isAlive()

checks if thread is still running or not

join()

Wait for a thread to end

run()

Entry point for a thread

sleep()

suspend thread for a specified time

start()

start a thread by calling run() method

 

>>> When we extend Thread class, setName() and getName() methods cannot be overridden, because they are declared final in Thread superclass.

 

>>> While using sleep() method, always handle the exception it throws.

Let’s dive into some code on how to create a Thread in Java. Follow the below code fragment:

 

 

class MyThread extends Thread {
public void run() {
 System.out.println("Concurrent thread started running..");
}
}

classMyThreadDemo {
public static void main( String args[] ){
 MyThread mt = new  MyThread();
 mt.start();
}
}

The extending class must override run() method which is the entry point of new thread. Output will be:

 

Concurrent thread started running..

 

Use the start() method to start and run the thread.

implements Runnable interface

The easiest way to create a thread is to create a class that implements the runnable interface. After implementing runnable interface , the class needs to implement the run() method, which is of the form,

 

public void run()



  • run() method introduces a concurrent thread into your program. This thread will end when run() returns.
  • You must specify the code for your thread inside run() method.
  • run() method can call other methods, can use other classes and declare variables just like any other normal method.

 

Let’s look at the code snippet described above:

 

 

class MyThread implements Runnable {
public void run() {
 System.out.println("concurrent thread started running..");
}
}

class MyThreadDemo {
public static void main( String args[] ) {
 MyThread mt = new MyThread();
 Thread t = new Thread(mt);
 t.start();
}
}

Output for the above code will be:

 

concurrent thread started running..

 

To call the run() method, start() method is used. On calling start(), a new stack is provided to the thread and run() method is called to introduce the new thread into the program.

Calling run() without start()

In the above program if we directly call run() method, without using start() method,

 

 

public static void main( String args[] ) {
MyThread mt = new MyThread();
mt.run();
}

Doing so, the thread won't be allocated a new call stack, and it will start running in the current call stack, that is the call stack of the main thread. Hence Multithreading won't be there.

implement Runnable vs extends Thread

Runnable is the preferred way to do it. We’re not really specialising the thread's behaviour and just giving it something to run. That means composition is the philosophically "purer" way to go.

 

In practical terms, it means we can implement Runnable and extend from another class as well, giving free signal to use more super properties.

Forcibly stopping a Thread

We can stop a thread using stop() method on it though it is not recommended at all. This is so important that we will state it again.

 

>>> Do not call the deprecated stop() method. It is unsafe. It causes the thread to abort no matter what it's doing, and it could be in the middle of executing a critical section with data in an inconsistent state.

The synchronized Statement

Every object has a monitor which can be locked and unlocked. The monitor can only be owned by one thread at a time. If the monitor is owned by t1 and a different thread t2 wants it, t2 blocks. When the monitor gets unlocked, the threads blocked on the monitor compete for it and only one of them gets it.

 

The monitor for object o is only acquired by executing a synchronized statement on o:

 

 

synchronized (o) {
       ...
   }

The lock is freed at the end of the statement (whether it completes normally or via an exception).

You can mark methods synchronized as shown in following snippet:

 

 

class C {
   synchronized void p() {...}
   static synchronized void q() {...}
   ...
}

but this is just syntactic sugar for

 

 

class C {
   void p() {synchronized (this) {...}}
   static void q() {synchronized(C.class) {...}}
   ...
}

The synchronized statement is used to enforce mutual exclusion. When multiple threads access the same piece of data, it's imperative that one thread not see the data in an intermediate state. Example is shown:

 

class PriorityQueue {
   // Implemented as a binary heap
   private Object[] data;
   private int size;
   ...
   public synchronized add(Object o) {
       if (size == data.length) {
           throw new HeapFullException();
       }
       data[size++] = o;
       siftUp();
   }
   public synchronized Object remove() {
       ...
   }
   public synchronized String toString() {
       ...
   }
}

If the methods add() and remove() are not synchronized several problems could occur.

Advantages of Threads

  • Threads minimize the context switching time.
  • Use of threads provides concurrency within a process.
  • Efficient communication.
  • It is more economical to create and context switch threads.
  • Threads allow utilization of multiprocessor architectures to a greater scale and efficiency.

Conclusion

In this tutorial, we studied the concept of threads in Java. From what they are, how to classify them, break them and used them. We also had a look at synchronisation.

By Shubham Aggarwal | 1/19/2017 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now