Threading and Synchronization

Reading Time: 9 minutes

In this blog, we will learn about threading and synchronization in java

What is a Java Thread ?

A thread, in the context of Java, is the path followed when executing a program. All Java programs have at least one thread, known as the main thread, which is created by the Java Virtual Machine (JVM) at the program’s start when the main() method is invoked with the main thread.

In Java, creating a thread is accomplished by implementing an interface and extending a class. Every Java thread is created and controlled by the java.lang.Thread class.

A single-threaded application has only one thread and can handle only one task at a time. To handle multiple tasks in parallel, multi-threading is used: multiple threads are created, each performing a different task.

Why thread is used ?

1: For faster processing of background/batch tasks: When multiple tasks must be performed simultaneously, multi-threading allows the different tasks to proceed in parallel. The overall processing time is reduced as a result.

2:To take advantage of modern processors: Most modern systems have multiple processors and each processor has multiple cores. Multi-threading allows different threads to be run by different processors, thereby allowing the system resources to be more efficiently used.

3: For reducing response times: Users expect applications to be fast. By breaking the processing needed for a request into smaller chunks and having different threads handle the processing in parallel, response time can be reduced.

4: To serve multiple users at the same time: Application servers like Tomcat, JBoss, Oracle WebLogic and IBM WebSphere are expected to support thousands of users in parallel. Multi-threading is the only way this can be achieved. One thread is spawned by the application server for each request to be handled

Creation of thread

Threads can be created by using two mechanisms

1: Extending the thread class.

2: implementing the Runnable interface.

By extending the thread class

  • create one class by extending thread class.
  • Define the property if required.
  • Define the constructor to initialize that property if required.
  • override the following method in the custom thread class. public void run().
  • you need to use the following method to convert simple java object into thread and to excute the run() method automatically. public synchronized native void start().
  • The start() method can be invoked only one time with thread object. if you are trying to invoke the start() method multiple times explicitly then jvm will throw run time exception called java.lang.IllegalThreadStateException.

By implementing Runnable interface

  • you need to define one class by implemeting Runnable interface to create thread.
  • you need to override the following abstrct method: public void run()
  • if you are defining thread class by using Runnable interface then you cannot use start method with thread class object. To invoke the start method , you need to use object of type java.lang.Thread class.

Life cycle of thread

  • you will invoke the start method with thread object then thread will move to runnable state. it is also known as ready to run state.
  • one thread will selected from runnable state and moved to running state. The thread will selected depends upon the
  • cpu scheduler.
  • if the thread is in running state then it will executed by the processor.
  • when the sleep method will called then the thread will moved to sleep state. while calling the sleep method, you need to specify the time. The thread will remain in sleep state for the specified time. After completing the specified time, the thread will move to runnable state automatically.
  • when the wait method is call then the thread will move to wait state. while calling the wait method, you need to use one object. The thread that is using the object will moved to wait state.
  • while calling the wait method,you need to specify some time. if you are not specifying the time then the thread will remain in wait state and will not moved to runnable state. In this condition , you need to call notify and notifyAll method with the same object to transfer the thread into runnable state.
  • if you are specifying the time then thread will remain in wait state for the specified time and after completing the time, the thread will move to runnable state automatically.
  • you can move the thread from wait state to runnable state before completing the specified time. For this, you can use notify/notifyAll method.
  • The thread is processing the statement and required some resource that is not available then the thread will move to blocked state. when the resource will be available then thread will moved to runnable state.
  • calling the stop method will move thread to destroyed state and once the thread will destroy or start then it cannot restart.
  • if the resource is block by one thread then it will not used by another thread concurrently.
  • you are calling sleep method and if thread is locking any resource then lock will not released and thread will moved to sleep state.
  • calling wait method and if thread is locking any resource then lock will released so that other thread will use the reource and thread will move to wait state.
  • wait method must call from synchronized context.

Thread name

  • whenever the thread is create some default name will be assign to this thread.
  • The dfault name will be as follow Thread-<int value> int value starts with zero and increased by 1.
  • if you want to access the name of thread then you can use the following method with thread object: public final String getName()
  • After creating the thread , if you want to change the name of thread then you can use the following method with thread object: public final void setName(String name)
  • while creating the thread object if you want to provide the name of the thread then you can use the constructor of the thread as well.
public Thread(String name)
public Thread(Runnable runnable, String name)
public Thread(ThreadGroup tg,String name)
public Thread(ThreadGroup tg,Runnable runnable,String name).

Thread priority

  • After the creation of a thread, system assign priority to a thread called thread priority.
  • The priority will be use by scheduler to decide which thread will be execute first.
  • The thread with higher priority will be execute first then the thread will lower priority will executed.
  • The minimum priority will be 1 and the maximum priority will be 10. The 5 will be the normal priority.
  • you want to access the priority of the thread then you can use the below following method with the thread object. public final int getPriority().
  • you want to set the priority of the thread then you can use the below following method with the thread object. public void final setPriority(int p).
  • if you are providing the value of p that is other than 1 to 10 then it will throw run time exception called java.lang.IllegalArgumentException.

Thread Group

  • it is the class available in java.lang package. it will be use to collect multiple thread as single group.
  • when the JVM will be start then one thread group is create with the name call ‘main’ All the thread will be add to thread group called ‘main’.
  • if you want to access the thread group then you can use the following method: public final ThreadGroup getThreadGroup()
  • if you want, you can define the custom thread group also and you can add the thread in the custom thread group.
  • To specify the thread group information, you can use the following constructor from the thread class. public Thread(ThreadGroup tg, Runnable runnable) public Thread(ThreadGroup tg, String name) public Thread(ThreadGroup tg, Runnable runnable,String name)

Daemon thread

  • it is a special type of thread that will be use to provide the service to the main thread.
  • The name of this thread is service thread.
  • main thread is destroy then daemon thread is also destroy.
  • if you want to known wheather one thread is daemon or not then you can use the following method with thread object. public final boolean isDaemon()
  • if you want to define one thread as daemon then you can use the following method with the thread object class.
    • public final void setDaemon(boolean value)

Multithreading

  • Multithreading is a process of executing two or more threads simultaneously.
  • A Java application starts with a single thread – called the main thread – associated with the main() method. This main thread can then start other threads.
  • Threads are lightweight, which means that they run in the same memory space. Hence, they can easily communicate among themselves.

Yield method

  • Suppose there are three threads t1,t2 and t3. Thread t1 gets the processor and starts its execution and thread t2 and t3 are in ready/Runnable state. if thread t1 takes 5 hour to complete it’s execution and thread t2 takes only 5 min to complete it’s execution then thread t2 has to wait up to 5 hour. In this condition, we can pause the execution of thread t1 and give processor to thread t2 so that thread t2 completes it’s execution and after that thread t1 continue it’s execution. To suspend the excution of current thread, we can use yield() method.
  • if any thread executes yield() method then thread scheduler check whether any thread with same or higher priority is available or not.if available then pause the current thread execution and move the current thread to Ready/Runnable state and give the processor to other thread. if not available then current thread continue it’s execution.
  • if any thread executes yield() method and thread scheduler find that there are many thread with priority are available then we cannot specify which thread will get the processor to execute.
  • The thread which execute yield() method will move to runnable state from running state.

sleep method

This method moves the currently executing thread to the sleep state for the specified time.

Join method

  • it is use to join one thread at the end of another thread.
  • join method just take the currently running thread and add it to the end of thread on which join method is call.
    • Ex : Thread t = new Thread(); t.start(); t.join();
    • In this case, thread t first complete its execution then other thread resumes and start its execution.
  • This will give guarantees that thread t will complete its execution without giving any chance to other thread.
  • Suppose there are two threads t1 and t2 . Thread t2 exceutes after completing the thread t1. In such case, we can use join method on thread t1 so that thread t1 first complete its execution then other thread start its execution.
    • Thread t1 = new Thread();
    • Thread t2 = new Thread();
    • t1.start();
    • t1.join();
    • t2.start();
  • This will ensure that first thread t1 complete its execution then thread t2 start its execution.

Synchronization

  • it is the process of locking the object. By using this concept, you can enable lock on the object.
  • if the object is lock by one thread then it cannot be access by multiple thread concurrently.
  • Synchronization will be decrease the concurrency.
  • Synchronization will used to lock the object.
  • you can define the synchronization in two ways
    • Method level synchronization.
    • Block level synchronization

Method level synchronization

Syntax: [modifier] synchronization <returnType> <methodName>(<params>) [throws…]{

// statements

}

  • In the method level synchronization, you are defining the method with synchronization modifier.
  • The object that will be use to invoke the synchronized method will be lock by thread.

Block level synchronization

Syntax: synchronized(<objReferences>){

// implementation

}

  • In this condition, the object that will be provide as the arguments to the synchronized block will be lock.
  • If the object will be lock then it cannot be use by multiple threads concurrently to invoke the synchronized method.
  • The object can be use by multiple thread concurrently to invoke non-synchronized method.
  • if you are invoking any method then first method will be verifies wheather it is synchronize or not.
  • The method will not be synchronize then it will be invoke concurrently.
  • Method will be synchronize then jvm will be verify wheather the object is lock by another thread or not.
  • if it is lock by another thread then the object cannot be use to invoke the method.
  • if the object is not lock then it will be use to invoke the synchronized method and object will be lock by current thread.

Thread Pools in Java

  • A thread pool is a collection of pre-initialized threads.
  • It facilitates the execution of N number of tasks using the same threads. If there are more tasks than threads, then tasks need to wait in a queue like structure (FIFO – First in first out).
  • When any thread completes its execution, it can pickup a new task from the queue and execute it.
  • Thread pool reuses previouly created thread to execute the current task.
  • if we create new thread for every request and destroy that thread after completing the request then it will time consuming and slow the performence of application. Sometimes,it will cause the system out of memory error because new thread consume system resources.
  • To overcome this issue, thread pool concept is use in which we use the previously created thread to execute the current task.
  • For thread pool , java introduce executor framework. we use ExecutorService interface and ThreadPoolExecutor class for that.
  • To use thread pools, we create object of ExecutorService and pass a set of tasks to it. ThreadPoolExecutorService class allow to set maximum pool size.
  • newFixedThreadPool(int) : This will creates a fixed size thread pool.
  • NewCachedThreadPool() : This will creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available
  • newSingleThreadExecutor() : This will creates a single thread.
  • In case of fixedThreadPool , if all thread run by the executor then the pending tasks are place in queue and when thread is available then it will start executing the pending task place in queue.
  • ThreadPoolExecutor separates the task creation and its execution. With ThreadPoolExecutor, you only have to implement the Runnable objects and send them to the executor.

Example of custom thread pool

public class CustomThreadPoolTestMain {

	 public static void main(String[] args) {
	        CustomThreadPool customThreadPool = new CustomThreadPool(2);
	        for (int i = 1; i <= 5; i++){
	        	CustomTask task = new CustomTask("Task " + i);
	            System.out.println("Created : " + task.getName());
	            customThreadPool.execute(task);
	        }
	    }

}


import java.util.concurrent.LinkedBlockingQueue;

public class CustomThreadPool {

	// Thread pool size
	private final int poolSize;

	// Internally pool is an array
	private final WorkerThread[] workers;

	// FIFO ordering
	private final LinkedBlockingQueue<Runnable> queue;

	public CustomThreadPool(int poolSize) {
		this.poolSize = poolSize;
		queue = new LinkedBlockingQueue<Runnable>();
		workers = new WorkerThread[poolSize];

		for (int i = 0; i < poolSize; i++) {
			workers[i] = new WorkerThread();
			workers[i].start();
		}
	}

	public void execute(Runnable task) {
		synchronized (queue) {
			queue.add(task);
			queue.notify();
		}
	}

	private class WorkerThread extends Thread {
		public void run() {
			Runnable task;
			while (true) {
				synchronized (queue) {
					while (queue.isEmpty()) {
						try {
							queue.wait();
						} catch (InterruptedException e) {
							System.out.println("An error occurred while queue is waiting: " + e.getMessage());
						}
					}
					task = (Runnable) queue.poll();
				}

				try {
					task.run();
				} catch (RuntimeException e) {
					System.out.println("Thread pool is interrupted due to an issue: " + e.getMessage());
				}
			}
		}
	}

	public void shutdown() {
		System.out.println("Shutting down thread pool");
		for (int i = 0; i < poolSize; i++) {
			workers[i] = null;
		}
	}

}

Knoldus-blog-footer-image

Written by 

I am a java developer having 6 years of experience. I have worked on Core Java, Spring, Spring boot, Kafka, Spark, MySQL. I am curious about learning new technologies.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading