Different Approaches to Concurrent Programming in Java


In Java, concurrent programming is a technique that allows multiple tasks or processes to run simultaneously on a single processor or multiple processors. It can improve the performance and responsiveness of applications. However, it also introduces new challenges and complexities to the Java developers, such as synchronization and deadlock. In this article, we will explore some of the different approaches to concurrent programming such as multithreading and executors.

Concurrent Programming in Java

The following three components of Java are used for Concurrent Programming

  • java.lang.Thread clas

  • java.lang.Runnable

  • java.util.concurrent

Multithreading

It is a feature of the Java programming language that allows us to perform multiple operations simultaneously. In it, the operation gets divided into multiple smaller parts called a thread. Each thread performs one independent task without affecting the other thread’s performance. The main benefit of multithreading is the optimal use of resources like CPU and it boosts the execution time of allocated operations.

There are two ways to create threads in Java

  • By implementing Runnable Interface

  • By extending Thread class

In our next example, we will create threads by extending Thread class

Syntax

class nameOfThread extends Thread {
   // operations
}

Approach

  • Create a class named ‘Thrd’ and inside it define a static method named ‘operation()’ along with an argument.

  • Now, in this method, take a for loop that will run 4 times and increment the given argument. The try block of this loop will print the output with a specified time interval i.e. 1000 milliseconds

  • Moving further, create three Threads. Inside these threads pass the arguments to the ‘operation()’ method.

  • At last, in the main method create three objects for the thread class and execute them using the inbuilt method ‘start()’.

Example of Thread

The following example demonstrates what we have discussed till this point about multithreading

class Thrd {
   public static void operation(int data) {
      for(int i = 1; i <= 4; i++) {
      System.out.println(data++);
      try {
         // each iteration performed with interval of 1 sec
         Thread.sleep(1000);
         } catch(Exception exp){}
      }
   }
}
class Thrd1 extends Thread { // thread number 1
   public void run() {
      Thrd.operation(1);
   }
}
class Thrd2 extends Thread { // thread number 2
   public void run() {
      Thrd.operation(5);
   }
}
class Thrd3 extends Thread { // thread number 3
   public void run() {
      Thrd.operation(10);
   }
}
public class ThrdExecution {
   public static void main(String args[]) {
      // creating object for thread class
      Thrd1 oprt1 = new Thrd1();
      Thrd2 oprt2 = new Thrd2();
      Thrd3 oprt3 = new Thrd3();
      // Starting the thread operation
      oprt1.start();
      oprt2.start();
      oprt3.start();
   }
}

Output

1
10
5
2
11
6
3
12
7
4
13
8

Executor

It is an interface of Java Concurrent API that can initiate and control the thread execution. It defines three predefined classes named ThreadPoolExecutor, ForkJoinPool, and ScheduledThreadPoolExecutor. These classes further implements Executor and ExecutorService interfaces to manage threads.

But, most of the time we use static factory methods for creating different kinds of executor services defined by the Executors utility class −

  • newCachedThreadPool()

  • newFixedThreadPool()

  • newScheduledThreadPool()

Approach

  • The first step is to import the ‘java.util.concurrent’ package to enable the use of Executor.

  • Now the rest of the code works similarly to the first example except for the main() method.

  • In the main() method, define an executor using ‘newFixedThreadPool()’ and using its instance with built-in method ‘execute()’ start the execution of threads.

Example of Executor

The following example illustrates the use of newFixedThreadPool() with the threads.

import java.util.concurrent.*;
class Thrd {
   public static void operation(int data) {
      for(int i = 1; i <= 4; i++) {
         System.out.println(data++);
         try {
            // each iteration performed with interval of 1 sec
            Thread.sleep(1000);
         } catch(Exception exp){}
      }
   }
}
class Thrd1 extends Thread { // thread number 1
   public void run() {
      Thrd.operation(1);
   }
}
class Thrd2 extends Thread { // thread number 2
   public void run() {
      Thrd.operation(5);
   }
}
class Thrd3 extends Thread { // thread number 3
   public void run() {
      Thrd.operation(10);
   }
}
public class ThrdExecution {
   public static void main(String args[]) {
      // creating executer service
      ExecutorService es = Executors.newFixedThreadPool(3);
      // starting execution
      es.execute(new Thrd1());
      es.execute(new Thrd2());
      es.execute(new Thrd3());
   }
}

Output

1
5
10
2
6
11
3
7
12
8
4
13

Conclusion

We have discussed various approaches to concurrent programming in Java like threads and executors. Each approach has its own benefits and drawbacks depending on the needs. Here, threads are the basic unit of concurrency.

Updated on: 21-Jul-2023

114 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements