Software Training Institute in Chennai with 100% Placements – SLA Institute

Easy way to IT Job

Share on your Social Media

What is Java Multithreading? Concurrency and Synchronization with Examples

Published On: April 28, 2023

The term concurrency refers to a measure of – or the art of improving – how effectively an application enables multiple jobs demanded by that application (e.g. allowed to serve web page requests from a web server) to run concurrently. Synchronization generally refers to sharing data between multiple processors or threads. In this article, we are explaining Java multithreading, concurrency in Java, and Synchronization in Java with examples. Yet to start with Java? Book a free demo at SLA to know the specialization of our Java Training in Chennai.

Multithreading in Java

The multithreading functionality of Java enables the concurrent execution of multiple threads. The smallest unit of processing is a thread, which is a small sub-process. Multitasking is accomplished using both multiprocessing and multithreading. As threads employ a shared memory space, we prefer multithreading to multiprocessing. 

They conserve memory by not allocating separate memory areas, and context switching between the threads is quicker than the process. Animated films and video games are the main uses of Java multithreading.

Java multithreading has a few benefits 

  • As threads are autonomous and you can do several actions simultaneously, the user is not blocked.
  • It saves time since multiple procedures can be completed simultaneously.
  • As each thread is autonomous, if an exception arises in one thread, it does not affect the other threads.

Sample Program: It uses multiple threads to carry out a single task

File Name: ExMultitasking1.Java

class TestMultitasking1 extends Thread{  

public void run(){  

    System.out.println(“task one”);  

  }  

  public static void main(String args[]){  

TestMultitasking1 t1=new TestMultitasking1();  

TestMultitasking1 t2=new TestMultitasking1();  

TestMultitasking1 t3=new TestMultitasking1();    

  t1.start();  

  t2.start();  

  t3.start();  

 }  

}  

Output

task one

task one

task one

File Name: ExMultitasking2.Java

class TestMultitasking2 implements Runnable{  

public void run(){  

System.out.println(“task one”);  

}  

public static void main(String args[]){  

Thread t1 =new Thread(new TestMultitasking2());//passing anonymous object of TestMultitasking2 class  

Thread t2 =new Thread(new TestMultitasking2());  

t1.start();  

t2.start(); } }  

Output

task one

task one

Concurrency in Java

Concurrency in Java (multi-threading). It explains how to use Java for concurrent programming. Parallel programming, immutability, threads, the executor framework (thread pools), futures, callables CompletableFuture, and the fork-join framework are all covered.

What is Concurrency?

The capacity to run several programs or multiple segments of a program simultaneously is known as concurrency. A time-consuming task can be carried out asynchronously or in parallel, which boosts the program’s throughput and interactivity.

Modern computers include many CPUs or multiple cores within a single CPU. Using these multi-cores effectively may be the secret to a high-volume application’s success.

Process vs Threads

A process operates separately from other processes. Direct access to shared data in other processes is not possible. The operating system allocates the process’s resources, such as memory and CPU time.

A so-called lightweight process is a thread. Although it can access shared data from other threads in the same process, it has its own call stack. Each thread has a dedicated memory cache. Any shared data that a thread reads is kept in its own memory cache.

The shared data can be read again by a thread.

By default, a Java application runs in a single process. In a Java application, you can provide asynchronous or parallel processing by using several threads.

Concurrency Improvements and Issues

Limits of Concurrency Gains

In a Java application, you can provide asynchronous or parallel processing by using several threads. Because tasks can be broken down into smaller ones and carried out in parallel, concurrency promises to speed up some tasks. Of course, the runtime is constrained by the tasks’ parallelizable components.

The following formula, known as Amdahl’s Law, can be used to compute the theoretically feasible performance boost.

The greatest performance increase is 1 / (F+ ((1-F)/N)) if F is the proportion of the program that cannot run in parallel and N is the number of processes.

Concurrency Issues

Although they can access common data, threads have their own call stack. As a result, you are faced with visibility and access issues. If thread A receives shared data that is subsequently updated by thread B without thread A being aware of the change, this is known as a visibility problem. When many threads simultaneously access and modify the same shared data, an access issue may arise. Do you want to know the difference between method overloading and method overriding in Java? Read our recent article.

Problems with visibility and access may result in:

  • Failure of liveness occurs when the program no longer responds as a result of issues with concurrent data access, such as deadlocks.
  • Error in data created by the program, a safety failure.

Threads and Processes

A Java program typically runs in one thread and its own process. The Thread code in Java allows for the support of threads. Via the use of this class, the Java program can start new threads. Together with enhanced concurrency functionality, Java 1.5 now includes the java.util.concurrent package.

Locks and Thread Synchronization

Java offers locks to secure specific code sections from simultaneous execution by multiple threads. The simplest way to lock a particular Java class or method is to specify it with the synchronized keyword.

Java’s synchronized keyword makes sure:

  • that implies a block of code can only be run by a single thread at once
  • that each thread entering a synchronized section of code sees the results of every modification made previously and is protected by the same lock.

For mutually exclusive access to blocks of data and trustworthy thread-to-thread communication, synchronization is required.

The keyword “synchronized” can be used while defining a method. This would guarantee that only one thread may access this method at once. A subsequent thread that is invoking this function will wait until the initial thread exits it.

public synchronized void critical() {

    // some thread critical stuff

    // here

}

The synchronized keyword can also be used to secure sections of code inside a method. A key, which may be a string or an object, is in charge of protecting this block. The lock key is what it is called. Only one thread may execute all code that is secured by the same lock at once.

In the case of the add() and next() methods, for instance, the following data structure will guarantee that only one thread can access the inner block.

package de.vogella.pagerank.crawler;

import java.util.ArrayList;

import java.util.List;

public class CrawledSites {

    private List<String> crawledSites = new ArrayList<String>();

    private List<String> linkedSites = new ArrayList<String>();

    public void add(String site) {

        synchronized (this) {

            if (!crawledSites.contains(site)) {

                linkedSites.add(site);

            }

        }

    }

    public String next() {

        if (linkedSites.size() == 0) {

            return null;

        }

        synchronized (this) {

            // Need to check again if the size has changed

            if (linkedSites.size() > 0) {

                String s = linkedSites.get(0);

                linkedSites.remove(0);

                crawledSites.add(s);

                return s;

            }

            return null;

        }

    }

}

Synchronization in Java

Java’s synchronization mechanism makes it possible to control how many threads can access any given shared resource. Java Synchronization is a better option if we just want one thread to be able to access the shared resource. Know what is the current job market trend for certified Java professionals through our blog.

Why should we use synchronize?

Generally, synchronization is utilized 

  • to avoid thread interference.
  • to avoid consistency issues.

Types of Synchronization in Java

Two different methods of synchronization exist.

  • Process Synchronization
  • Thread Synchronization

Thread Synchronization in Java

Inter-thread communication and mutual exclusive are two categories into which thread synchronization can be divided.

  • Mutual Exclusive
    • Synchronization Method
    • Synchronization Block
    • Static Synchronization
  • Cooperation (Inter-thread communication).

Mutual Exclusive

While sharing data, mutual exclusivity prevents threads from interfering with one another. Three methods can be used to do it:

  • Using Synchronized Technique
  • With the help of Synchronized Block
  • Static Synchronization is Used

Lock Concept in Java

A crucial component of synchronization is an internal object known as the lock or monitor. There is a lock attached to every item. 

According to tradition, a thread that needs consistent access to an object’s fields must first lock the object before using it, then release the lock after it is done.

The java.util.concurrent.locks package has several lock implementations as of Java 5.

Synchronization Method in Java

If you declare a method to be synchronized, it is referred to as such.

Using a synchronized method implies locking an object for any shared resource.

When a synchronized method is called, a thread automatically acquires the lock for the object and releases the lock when it is done.

Example

File Name: ExSynchronization.Java

class Table{  

 synchronized void printTable(int n){//synchronized method  

   for(int i=1;i<=5;i++){  

     System.out.println(n*i);  

     try{  

      Thread.sleep(400);  

     }catch(Exception e){System.out.println(e);}  

   }  

  }  

}  

class MyThread1 extends Thread{  

Table t;  

MyThread1(Table t){  

this.t=t;  

}  

public void run(){  

t.printTable(5);  

}  

}  

class MyThread2 extends Thread{  

Table t;  

MyThread2(Table t){  

this.t=t;  

}  

public void run(){  

t.printTable(100);  

}  

}  

public class TestSynchronization2{  

public static void main(String args[]){  

Table obj = new Table();//only one object  

MyThread1 t1=new MyThread1(obj);  

MyThread2 t2=new MyThread2(obj);  

t1.start();  

t2.start();  

}  

}  

Output

       5

       10

       15

       20

       25

       100

       200

       300

       400

       500

Wrapping Up

Concurrency can be utilized within a process to offer the user numerous simultaneous services, which is one benefit of multithreading. Because concurrent threads can more easily exchange resources, multithreading also requires less processing overhead than multiprogramming.

You might want to schedule access to shared resources from time to time. For instance, you might not want one thread changing a database record while another thread tries to read it in a database system. Java gives you the ability to use synchronized methods and synchronized statements to control the operations of several threads. Gain expertise with Java Multithreading, Concurrency in Java, and Synchronization in Java with Best Practices through our Java Training in Chennai at SLA Institute. 

Share on your Social Media

Just a minute!

If you have any questions that you did not find answers for, our counsellors are here to answer them. You can get all your queries answered before deciding to join SLA and move your career forward.

We are excited to get started with you

Give us your information and we will arange for a free call (at your convenience) with one of our counsellors. You can get all your queries answered before deciding to join SLA and move your career forward.