March 28, 2024

Java Stream limit() Method with Examples

limit(long maxSize) method in the Java Stream API truncates the stream so that it is no longer than maxSize in length and returns the new stream with limited elements.

limit method in Java Stream

Syntax of the method is as given below.

Stream<T> limit(long maxSize)

Here maxSize is the limit on the number of elements stream should be truncated to. If you pass maxSize as negative then IllegalArgumentException is thrown.

Points about limit method

  1. It is a short-circuiting stateful intermediate operation which means it will return a new Stream. An intermediate operation is short-circuiting if, when presented with infinite input, it may produce a finite stream as a result.
  2. limit() is generally a cheap operation on sequential stream pipelines.
  3. limit() can be quite expensive on ordered parallel pipelines, if n is a fairly large values, because of the constraint to skip first n elements in the encounter order.

limit() Java Example

1. In the following example we’ll generate 10 random numbers. Initially generate() method of the java.util.stream is called to create an infinite Stream which generates random numbers of type double. Using map operation of Stream API these random numbers are then transformed to type int and having two digits. limit() method is then used to limit the stream to 10 elements.

import java.util.stream.Stream;

public class LimitDemo {
  public static void main(String[] args) {
    Stream.generate(Math::random).map(n -> (int)(n * 100)).limit(10).forEach(System.out::println);
  }
}
Output
16
64
17
97
18
5
16
74
50
87

2. In this example we’ll try to get a sublist from a List using limit() method to truncate the original list. Method getSubList() is a generic method that can work with any type of List, second argument passed to the method is the number of elements list should be limited to. Results of the stream returned by limit() method are collected to a list and that new list is returned.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LimitDemo {
  public static void main(String[] args) {
    LimitDemo ld = new LimitDemo();
    // Used with list of Strings
    List<String> cityList = Arrays.asList("Delhi", "Mumbai", "London", "New York","Bengaluru");
    List<String> newList = ld.getSubList(cityList, 3);
    System.out.println("List after limiting elements- " + newList);
    // Used with list of Integers
    List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    List<Integer> tempList = ld.getSubList(numList, 6);
    System.out.println("List after limiting elements- " + tempList);
  }
  
  // This method uses skip method to skip n elements
  public <T> List<T> getSubList(List<T> originalList, long maxSize){
    return originalList.stream().limit(maxSize).collect(Collectors.toList());
  }
}
Output
List after limiting elements- [Delhi, Mumbai, London]
List after limiting elements- [1, 2, 3, 4, 5, 6]

That's all for the topic Java Stream limit() Method with Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

March 27, 2024

Java Stream - Convert a Stream to List

In this tutorial you’ll see how to convert a Stream to list using collector method and utility methods like toList() and toCollection() of Collectors class in Java Stream API.

1. A simple example to collect Stream elements into an ArrayList.

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamToList {

  public static void main(String[] args) {
    Stream<String> streamElem = Stream.of("A", "B", "C", "D");
    List<String> listFromStream = streamElem.collect(Collectors.toList());
    System.out.println(listFromStream.getClass().getName());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
java.util.ArrayList
Elements in the list- [A, B, C, D]

As you can see type of the List returned is ArrayList.

2. If you want to convert the Stream into a LinkedList then you can use Collectors.toCollection() method.

public class StreamToList {

  public static void main(String[] args) {
    Stream<String> streamElem = Stream.of("A", "B", "C", "D");
    List<String> listFromStream = streamElem.collect(Collectors.toCollection(LinkedList :: new));
    System.out.println(listFromStream.getClass().getName());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
java.util.LinkedList
Elements in the list- [A, B, C, D]

As you can see now the type of the List is LinkedList.

3. Converting Stream to List while filtering some of the elements by providing a condition. For example if you want to store only those elements in the List which are greater than 10 then you can filter other elements.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamToList {
  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    List<Integer> listFromStream = numList.stream().filter(e -> e > 10).collect(Collectors.toList());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
Elements in the list- [12, 22]

4. An example with custom object to store only those Students in the List who have scored more than 90.

Student class used is as follows-
public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public String getName() {
    return name;
  }

  public String getStream() {
    return stream;
  }

  public int getMarks() {
    return marks;
  }

  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() 
        + " Name: " + getName() + " Marks: " + getMarks();
  }
}
public class StreamToList {
  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 75));
    List<Student> listFromStream = studentList.stream().filter(s -> s.getMarks() > 90).collect(Collectors.toList());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
Elements in the list- [Roll Number: 2 Name: Ram Marks: 99, Roll Number: 4 Name: Jacques Marks: 97]

5. If you want to get only the student names in the list then you can use map method along with collect.

public class StreamToList {
  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 75));
    List<String> listFromStream = studentList.stream().map(s -> s.getName()).collect(Collectors.toList());
    System.out.println("Elements in the list- " + listFromStream);
  }
}
Output
Elements in the list- [Mercy, Ram, Priscilla, Jacques, Peter]

That's all for the topic Java Stream - Convert a Stream to List. If something is missing or you have something to share about the topic please write a comment.


You may also like

March 26, 2024

How to Convert double to String in Java

This post shows how you can convert double to String in Java.

1. Converting double to String using Double.toString() method

Wrapper class Double in Java has a toString() method that returns a string representation of the passed double argument which can be used to convert double to String in Java.

public class DoubleToString {
	public static void main(String[] args) {
	    double num = 3785.8945d;
	    String str = Double.toString(num);
	    System.out.println("Converted String value = " + str);
	}
}
Output
Converted String value = 3785.8945

2. Convert using String.valueOf() method

String.valueOf(double d)- Returns the string representation of the double argument.

public class DoubleToString {
  public static void main(String[] args) {
    double val = -134.76d;
    String str = String.valueOf(val);
    System.out.println("Converted String value = " + str);
  }
}
Output
Converted String value = -134.76

3. Converting using String concatenation

You can concatenate the double value with an empty string ("") using + operator, that will return the result as a String.

public class DoubleToString {
	public static void main(String[] args) {
	    double val = 26.89;
	    String str = val + "";
	    System.out.println("Type of str is- " + str.getClass().getSimpleName());
	}
}
Output
Type of str is- String

4. Converting using append method of StringBuilder or StringBuffer class

Both StringBuilder and StringBuffer classes have append() method where you can pass double as an argument. The append() method will append the string representation of the double argument to the sequence.

public class DoubleToString {
  public static void main(String[] args) {
    double val = -826.89;
    StringBuilder sb = new StringBuilder();
    sb.append(val);
    System.out.println("Converted String value = " + sb.toString());
  }
}
Output
Converted String value = -826.89

That's all for the topic How to Convert double to String in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

March 25, 2024

Java throw Keyword With Examples

In the post try-catch block we have already seen some examples of exceptions but all those exceptions are thrown by Java run time. You may choose to throw an exception explicitly in your Java code, that can be done using throw statement in Java.

General form of Java throw statement

The throw statement requires a single argument; a throwable object.

throw throwableObj;

Here throwableObj must be an instance of Throwable class or any of its subclass.

How to get Throwable class instance

If you want to throw an exception explicitly you can get this Throwable class instance in two ways-

  1. You can create an instance using new operator. See example.
  2. You can use the exception parameter of the catch block and rethrow the exception. See example.

If there is a throw statement in a Java code then execution stops as soon as throw statement is encountered. Nearest catch block is checked for the matching exception type, if catch block has the matching exception type then that block handles the thrown exception. If matching exception type is not found then the next higher context is checked and so on.

Throw statement example with new exception instance

As stated above one of the way you can throw exception in your code is by creating an exception instance using new operator.

public class ThrowDemo {
  public static void main(String[] args) {
    try{
      if(args.length != 2){
        throw new IllegalArgumentException("Two parameters should be passed");
      }
    }catch(IllegalArgumentException exp){
      System.out.println("Exception in the code " + exp.getMessage());
      exp.printStackTrace();
    }
  }
}
Output
Exception in the code Two parameters should be passed
java.lang.IllegalArgumentException: Two parameters should be passed
at com.knpcode.ThrowDemo.main(ThrowDemo.java:8)

In the above code exception is thrown if 2 arguments are not passed. The constructor used while creating exception instance is the one that takes String argument. That way you can pass a clear reason why exception is thrown. There is a method getMessage() method in Exception classes that can be used to display that message.

Java throw statement example when same exception is rethrown

You can also rethrow the exception that is caught in a catch block. One of the common reason to do that is to see if there is any exception handler for that specific exception which is thrown. As example if you have a catch block with Exception as exception type it will catch most of the exceptions since Exception is higher up in the exception hierarchy . You can rethrow that exception to be caught by an exception handler with the specific exception type.

public class ExceptionDemo {
  public static void main(String[] args) {
    ExceptionDemo ed = new ExceptionDemo();
    try{
      ed.division(7, 0);
    }catch(ArithmeticException exp){
      System.out.println("Exception occurred while dividing" + exp.getMessage());
      exp.printStackTrace();
    }
  }
	
  private void division(int num1, int num2){
    double result;
    try{
      result = num1/num2;
      System.out.println("Result" + result);
    }catch(Exception exp){
      System.out.println("Exception occurred while dividing" + exp.getMessage());
      throw exp;
    }	
  }
}
Output
Exception occurred while dividing/ by zero
java.lang.ArithmeticException: / by zero
	at com.knpcode.ExceptionDemo.division(ExceptionDemo.java:18)
	at com.knpcode.ExceptionDemo.main(ExceptionDemo.java:8)
Exception occurred while dividing/ by zero
java.lang.ArithmeticException: / by zero
	at com.knpcode.ExceptionDemo.division(ExceptionDemo.java:18)
	at com.knpcode.ExceptionDemo.main(ExceptionDemo.java:8)

In the above code division method has a catch block with parameter of class Exception. From there you are rethrowing the caught exception. In the calling method it is caught again by the catch block which has parameter of type ArithmeticException.

Rethrowing a different exception

You can also catch one type of exception and rethrow exception of another type using Java throw keyword. Actually it is a best practice for exception handling to do that when you are propagating exception through separate layers. That helps in preserving loose coupling of your code.

For example, in your DB layer SQLException is caught there is no sense in letting the same exception propagate to your business layer. In this case best thing to do is catch the SQLException which is a checked exception in your DAO layer and rethrow another exception (unchecked) that should propagate to business layer. You should send the original exception instance as a parameter.

catch(SQLException ex){
  throw new RuntimeException("Error in DB layer", ex);
}

That's all for the topic Java throw Keyword With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

March 24, 2024

Multiple Catch Blocks in Java

If hearing the term try-catch block is giving you an idea that you can have a try block and a single associated catch block then that is a wrong idea. You can have multiple catch blocks associated with a try block. In this post we’ll see examples of multiple catch blocks in Java exception handling.

Refer Multi-Catch Exception in Java to seen another way of grouping multiple catch blocks using multi-catch statement available from Java 7.

You enclose the code that may throw an exception in try block but the enclosed code may throw more than one exception too. In order to handle these exceptions you can provide multiple catch blocks in Java. If an exception is thrown the exception handling mechanism looks for the catch block with an argument that matches the type of the exception thrown. Only the matching catch clause out of the multiple catch blocks is executed. After the matching catch block is executed, execution continues after the try-catch block.

Example of multiple catch blocks in Java

In this example program there is an array of length 3 in the method calculateValue(). Index of the array is passed as an argument to the method. Since the array has value 0 at index 1 so passing 1 as an index will result in ArithmeticException because of the division by zero.

Same way passing 4 as an index will result in ArrayIndexOutOfBoundsException as the length of array is 3. To handle these multiple exception scenarios there are multiple catch blocks associated with the try block.

public class MultipleCatch {
  private void calculateValue(int i){
    int arr[] = {6, 0, 3};
    try{
      int num = 7/arr[i];
    }catch(ArithmeticException exp){
      exp.printStackTrace();
    }catch(ArrayIndexOutOfBoundsException exp){
      exp.printStackTrace();
    }catch(Exception exp){
      exp.printStackTrace();
    }
    System.out.println("After the try-catch block");
  }

  public static void main(String[] args) {
    MultipleCatch obj = new MultipleCatch();
    obj.calculateValue(1);
    obj.calculateValue(4);
  }
}
Output
java.lang.ArithmeticException: / by zero
	at com.knpcode.MultipleCatch.calculateValue(MultipleCatch.java:7)
	at com.knpcode.MultipleCatch.main(MultipleCatch.java:21)
After the try-catch block
java.lang.ArrayIndexOutOfBoundsException: 4
	at com.knpcode.MultipleCatch.calculateValue(MultipleCatch.java:7)
	at com.knpcode.MultipleCatch.main(MultipleCatch.java:22)
After the try-catch block

Maintaining exception hierarchy in multiple catch blocks

While using multiple catch blocks in Java you will have to keep exception hierarchy in mind, which means you will have to ensure that any exception super class doesn’t come before its exception sub-classes.

This should be ensured because a catch statement having an exception super class as an argument will be able to catch exception of its type and any of its subclass too. Thus, placing a catch statement having sub-class as an argument after the catch statement with super class as argument would mean the catch statement with sub-class is unreachable. Moreover unreachable code causes compile time error in Java so you will get compilation error for any such misplaced catch statement.

In the previous example the last catch statement has Exception class object as an argument to catch any other type of exception. Since Exception class is super class of both the ArithmeticException and ArrayIndexOutOfBoundsException so placing that catch statement first will result in compile time error. Just tweak the above example and place the catch statement with Exception class object as argument before the other catch blocks.

public class MultipleCatch {
  private void calculateValue(int i){
    int arr[] = {6, 0, 3};
    try{
      int num = 7/arr[i];
    }
    catch(Exception exp){
      exp.printStackTrace();
    }catch(ArithmeticException exp){
      exp.printStackTrace();
    }catch(ArrayIndexOutOfBoundsException exp){
      exp.printStackTrace();
    }
    System.out.println("After the try-catch block");
  }

  public static void main(String[] args) {
    MultipleCatch obj = new MultipleCatch();
    obj.calculateValue(1);
    obj.calculateValue(4);
  }
}

That will result in compile time error with compiler complaining about the unreachable code.

Unresolved compilation problems: 
	Unreachable catch block for ArithmeticException. It is already handled by the catch block for Exception
	Unreachable catch block for ArrayIndexOutOfBoundsException. It is already handled by the catch block for Exception

	at com.knpcode.MultipleCatch.calculateValue(MultipleCatch.java:11)
	at com.knpcode.MultipleCatch.main(MultipleCatch.java:21)

Important points

  1. There may be multiple catch blocks after a try block.
  2. If an exception is thrown in try block the catch block with matching exception type is executed.
  3. Only one of the multiple catch blocks is executed.
  4. Multiple catch blocks must be placed in the order specific to general.

That's all for the topic Multiple Catch Blocks in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

March 23, 2024

How to Create a Deadlock in Java

If you are asked what is deadlock in Java it is almost always accompanied by the question how to create a deadlock in Java.

Deadlock in multi-threading is a scenario where two or more threads are waiting for each other to release the resources to make any further progress and blocked forever in the process.

Java program for creating deadlock

You may get deadlock in Java when you have nested synchronized blocks with reverse ordering of objects.

In the example two threads are created to run two separate runnable tasks. In each runnable task there are nested synchronized blocks acquiring object locks in reversed order thus creating a deadlock.

class ThreadA implements Runnable{
  private Object obj1;
  private Object obj2;
  ThreadA(Object obj1, Object obj2){
    this.obj1 = obj1;
    this.obj2 = obj2;
  }
  @Override
  public void run() {
    synchronized(obj1){
      System.out.println(Thread.currentThread().getName() + " acquired " + "obj1 lock");
      System.out.println(Thread.currentThread().getName() + " waiting for " + "obj2 lock");
      synchronized(obj2){
        System.out.println(Thread.currentThread().getName() + " acquired " + "obj2 lock");
      }
    }       
  }  
}
 
class ThreadB implements Runnable{
  private Object obj1;
  private Object obj2;
  ThreadB(Object obj1, Object obj2){
    this.obj1 = obj1;
    this.obj2 = obj2;
  }
  @Override
  public void run() {
    synchronized(obj2){
      System.out.println(Thread.currentThread().getName() + " acquired " + "obj2 lock");
      System.out.println(Thread.currentThread().getName() + " waiting for " + "obj1 lock");
      synchronized(obj1){
        System.out.println(Thread.currentThread().getName() + " acquired " + "obj1 lock");
      }
    }   
  }
}

public class DLDemo {
  public static void main(String[] args) {
    Object obj1 = new Object();
    Object obj2 = new Object();
    Thread t1 = new Thread(new ThreadA(obj1, obj2));
    Thread t2 = new Thread(new ThreadB(obj1, obj2));
    t1.start();
    t2.start();
  }
}
Output
Thread-0 acquired obj1 lock
Thread-0 waiting for obj2 lock
Thread-1 acquired obj2 lock
Thread-1 waiting for obj1 lock

You can see in run() method of ThreadA synchronized block acquires lock on obj1 and then tries to acquire lock on obj2. Same way in run() method of ThreadB synchronized block acquires lock on obj2 and then tries to acquire lock on obj1. This hangs the program by creating a deadlock as t1 thread is waiting to acquire lock on obj2 which is currently acquired by t2 thread and t2 thread is waiting to acquire lock on obj1 which is currently acquired by the t1 thread.

Creating deadlock by calling one synchronized method from another

Here is another example of creating deadlock in Java. It is similar to the first example here rather than having nested synchronized blocks there are two synchronized methods. The objects which are used to call the method and the object which are passed as an argument to these methods are reversed thus creating deadlock.

public class DLDemo {
  public synchronized void method1(DLDemo obj){
    System.out.println(Thread.currentThread().getName() + " In Method1");
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    //Calling another synchronized method
    obj.method2(this);
  }
			  
  public synchronized void method2(DLDemo obj2){
    System.out.println("In Method2");
  }
 
  public static void main(String[] args) {
    DLDemo obj1 = new DLDemo();
    DLDemo obj2 = new DLDemo();
   
    new Thread(new Runnable() {
      public void run() { obj1.method1(obj2); }
    }).start();

    //Thread 2  
    new Thread(new Runnable() {
      public void run() { obj2.method1(obj1); }
    }).start();
  }
}
Output
Thread-0 In Method1
Thread-1 In Method1

From one thread synchronized method method1 is called using obj1 so this thread acquires a lock on obj1 then another synchronized method method2 is called using obj2.

From another thread synchronized method method1 is called using obj2 so this thread acquires a lock on obj2 then another synchronized method method2 is called using obj1.

That's all for the topic How to Create a Deadlock in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

March 22, 2024

Producer-Consumer Problem Java Program

In this post we’ll see Java program for producer-consumer problem using threads.

Producer consumer problem

Producer consumer is a classic concurrency problem where synchronization and inter thread communication is required for proper execution.

In producer-consumer problem there are two processes Producer and Consumer sharing a common bounded buffer known as queue.

  • Producer process generates data and inserts it into the shared queue.
  • Consumer process consumes data from the shared queue.

The requirement here is that Producer should not try to add data to the shared buffer if it is already full, it should rather wait for the queue to have space for new elements. Same way, Consumer should not try to consume data from an empty buffer, it should wait for data to be inserted in the queue.

Producer-consumer Java program

Since inter-thread communication is required for the proper implementation of Producer-Consumer so this program can be written using wait-notify methods.

You can also make use of the Java concurrency package where many queue implementations are added. Using ArrayBlockingQueue you can easily implement the Producer-Consumer program in Java.

Java program for Producer-consumer using wait-notify

In the Java program a shared buffer is required that is used by both producer and consumer processes for that a LinkedList instance can be used.

There also two Runnable tasks for producer and consumer which are executed by two separate threads. Once a value is added to the queue producer should notify consumer task to wake up and should go to wait state itself.

Same way consumer task should be in wait state if queue is empty.

import java.util.LinkedList;
// Producer task
class Producer implements Runnable{
  LinkedList<Integer> list;
  Producer(LinkedList<Integer> list){
    this.list = list;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){
      synchronized(list) {
        // If there is already an element in the list wait
        while(list.size() >= 1){
          System.out.println("Waiting as queue is full..");
          try {
            list.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        System.out.println("Adding to queue- " + Thread.currentThread().getName() + " " + i);
        list.add(i);
        list.notify();    
      }
    }		
  }
}
//Consumer task
class Consumer implements Runnable{
  LinkedList<Integer> list;
  Consumer(LinkedList<Integer> list){
    this.list = list;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){
      synchronized(list) {
        // if there is no element in the list wait
        while(list.size() < 1){
          System.out.println("Waiting as queue is empty..");
          try {
            list.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        // if there is element in the list then retrieve it
        System.out.println("Consuming from queue- " + Thread.currentThread().getName() + " " + list.remove());
        list.notify();  
      }
    }		
  }
}

public class ProducerConsumer {
  public static void main(String[] args) {
    // shared list
    LinkedList<Integer> list = new LinkedList<Integer>();
    Thread t1 = new Thread(new Producer(list), "Producer");
    Thread t2 = new Thread(new Consumer(list), "Consumer");
    t1.start();
    t2.start(); 
  }
}
Output
Adding to queue- Producer 1
Waiting as queue is full..
Consuming from queue- Consumer 1
Waiting as queue is empty..
Adding to queue- Producer 2
Waiting as queue is full..
Consuming from queue- Consumer 2
Waiting as queue is empty..
Adding to queue- Producer 3
Waiting as queue is full..
Consuming from queue- Consumer 3
Waiting as queue is empty..
Adding to queue- Producer 4
Waiting as queue is full..
Consuming from queue- Consumer 4
Waiting as queue is empty..
Adding to queue- Producer 5
Consuming from queue- Consumer 5

Java program for Producer-consumer using BlockingQueue

Using a BlockingQueue implementation like ArrayBlockingQueue you can easily implement the Producer-Consumer program in Java.

BlockingQueue has put() method for adding to the queue which blocks if the queue capacity is full. Same way there is a take() method for retrieving from the head of the queue which blocks if there is no element available.

In the code ArrayBlockingQueue of capacity 1 is created so queue will have only one element and the insertion will be blocked until that element is retrieved.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
// Producer task
class Producer implements Runnable{
  BlockingQueue<Integer> queue;
  Producer(BlockingQueue<Integer> queue){
    this.queue = queue;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){           
      try {
        queue.put(i);
        System.out.println("Adding to queue- " + i);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }   
    }
  }		
}
//Consumer task
class Consumer implements Runnable{
  BlockingQueue<Integer> queue;
  Consumer(BlockingQueue<Integer> queue){
    this.queue = queue;
  }
  @Override
  public void run() {
    for(int i = 1; i <= 5; i++){
      try {
        // if there is element in the list then retrieve it
        System.out.println("Consuming from queue- "  + queue.take());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }            
  }
}

public class ProducerConsumer {
  public static void main(String[] args) {
    BlockingQueue<Integer> bQueue = new ArrayBlockingQueue<Integer>(1);
    Thread t1 = new Thread(new Producer(bQueue), "Producer");
    Thread t2 = new Thread(new Consumer(bQueue), "Consumer");
    t1.start();
    t2.start(); 
  }
}
Output
Adding to queue- 1
Consuming from queue- 1
Adding to queue- 2
Consuming from queue- 2
Adding to queue- 3
Consuming from queue- 3
Adding to queue- 4
Consuming from queue- 4
Adding to queue- 5
Consuming from queue- 5

As you can see using ArrayBlockingQueue you don’t need to write logic for synchronizing threads and call wait and notify explicitly making it very simple to write producer-consumer Java program. It can be made more compact using Lambda expression.

public class ArrayBQ {
  public static void main(String[] args) {
    // BlockingQueue of capacity 1
    BlockingQueue<Integer> bQueue = new ArrayBlockingQueue<Integer>(1);
    // Producer 
    new Thread(()->{
      for(int i = 0; i < 5; i++){
        try {
          bQueue.put(i);
          System.out.println("Added to queue-" + i);  
          
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }).start();
        
    // Consumer
    new Thread(()->{
      for(int i = 0; i < 5; i++){
        try {
          System.out.println("Consumer retrieved- " + bQueue.take());
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }).start();
  }
}

That's all for the topic Producer-Consumer Problem Java Program. If something is missing or you have something to share about the topic please write a comment.


You may also like