What is JPA (Java Persistence API)?

JPA is a Java specification for object-relational mapping (ORM) in Java. JPA provide a way to map Java objects to database tables. This allows programmers to manipulate database information directly using Java objects instead of executing database SQL queries.

Developer can choose one of many available JPA specification implementation libraries such as Hibernate, Apache OpenJPA and EclipseLink. EclipseLink is the reference implementation of the JPA specification. In the examples that we are going to provide you in this website, Hibernate library will be used as the persistence provider.

In JPA we model our database tables into a Java objects. This Java objects also called as entity objects. The entity represent a table in database. A single row in a database table will be represented in an instance of the entity. This entity objects hold information about the mapping between objects and database tables. This information or metadata can be defined using an annotation or an XML mapping files.

Here is a simple example of entity object and its metadata information.

package org.kodejava.jpa.entity;

import javax.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;

@Entity
@Table(name = "genre")
public class Genre implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;

    private Long id;
    private String name;

    public Genre() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    @Column(nullable = false, length = 50)
    public String getName() {
        return name;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Genre genre = (Genre) o;
        return Objects.equals(id, genre.id) &&
                Objects.equals(name, genre.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

    @Override
    public String toString() {
        return "Genre{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

In the entity above we use annotation such as @Entity, @Table, @Id, @GeneratedValue and @Column. These are some annotations that you can use for object mapping.

Beside manipulating database tables using objects, JPA also provide a SQL-like queries that can be used to create a static or dynamic query statement.

Maven Dependencies

<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
</dependency>

Maven Central

How do I do math operations using Spring EL?

As we know that the simplest value that can be expressed in the Spring EL is a literal value such as number. Furthermore, we can also do math operations using the Spring EL. The spring configuration below show you how can do math operations using the Spring Expression Language. These operations include:

  • Add operation (+)
  • Subtract operation (-)
  • Multiply operation (*)
  • Divide operations (/)
  • Modulo operation (%)
  • Power operation (^)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBean" class="org.kodejava.spring.core.el.MyBean">
        <property name="total" value="#{50 + 50}" />
        <property name="length" value="#{100 - 10}" />
        <property name="size" value="#{10 * 10}" />
        <property name="reminder" value="#{10 % 3}" />
        <property name="distance" value="#{1000 / 10}" />
        <property name="power" value="#{2 ^ 10}" />
    </bean>

</beans>

The configuration above requires a bean / pojo called MyBean. It’s a simple class with some fields and getters and setters. Followed later by a simple class called SpELMathOperationDemo that demonstrate the Spring EL math operations.

package org.kodejava.spring.core.el;

public class MyBean {
    private int total;
    private int length;
    private int size;
    private float distance;
    private int reminder;
    private int power;

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public float getDistance() {
        return distance;
    }

    public void setDistance(float distance) {
        this.distance = distance;
    }

    public int getReminder() {
        return reminder;
    }

    public void setReminder(int reminder) {
        this.reminder = reminder;
    }

    public int getPower() {
        return power;
    }

    public void setPower(int power) {
        this.power = power;
    }
}
package org.kodejava.spring.core.el;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpELMathOperationDemo {
    public static void main(String[] args) {
        try (ClassPathXmlApplicationContext context =
                     new ClassPathXmlApplicationContext("spel-math-operation.xml")) {
            MyBean bean = (MyBean) context.getBean("myBean");
            System.out.println("bean.getTotal()    = " + bean.getTotal());
            System.out.println("bean.getLength()   = " + bean.getLength());
            System.out.println("bean.getSize()     = " + bean.getSize());
            System.out.println("bean.getReminder() = " + bean.getReminder());
            System.out.println("bean.getDistance() = " + bean.getDistance());
            System.out.println("bean.getPower()    = " + bean.getPower());
        }
    }
}

And these are the output printed out by the code snippet:

bean.getTotal()    = 100
bean.getLength()   = 90
bean.getSize()     = 100
bean.getReminder() = 1
bean.getDistance() = 100.0
bean.getPower()    = 1024

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I call static method using Spring EL?

In this example you will learn how to call static method using Spring EL. The T() operator of the Spring EL can be used to call static method. First, create the following class, NumberGenerator. This class has a single property randomNumber and getter / setter method.

package org.kodejava.spring.core.el;

public class NumberGenerator {
    private int randomNumber;

    public int getRandomNumber() {
        return randomNumber;
    }

    public void setRandomNumber(int randomNumber) {
        this.randomNumber = randomNumber;
    }
}

Now, create the following spring configuration file and save it in a file called SpELStatic.xml. In this configuration we register a bean called bean of type NumberGenerator. We set its randomNumber property using the value produced by the java.lang.Math.random() static method. For calling a static method we use the Spring EL T() operator, for example #{T(java.lang.Math).random()}.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bean" class="org.kodejava.spring.core.el.NumberGenerator">
        <property name="randomNumber" value="#{T(java.lang.Math).random() * 100 + 1}" />
    </bean>

</beans>

The program below load the spring configuration and get the NumberGenerator bean to create a random number.

package org.kodejava.spring.core.el;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StaticELDemo {
    public static void main(String[] args) {
        try (ClassPathXmlApplicationContext context =
                     new ClassPathXmlApplicationContext("spel-static.xml")) {

            NumberGenerator number = (NumberGenerator) context.getBean("bean");
            System.out.println("Random number: " + number.getRandomNumber());
        }
    }
}

And example result you might get when running the program:

Random number: 33

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I handle or avoid null value in Spring EL?

In this example you will learn how to avoid a null value, which causing a NullPointerException thrown in a Spring EL expression. To avoid this from happening we can use the null-safe accessor, using the ?. operator.

We are using the previous example, How do I inject bean’s property using Spring EL? classes, which are the Student class and the Grade class. What we need is to create a new spring configuration file to demonstrate this feature. So, here is the configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="org.kodejava.spring.core.el.Student">
        <property name="name" value="Alice" />
        <property name="grade" value="#{grade.getName()?.toUpperCase()}" />
    </bean>

    <bean id="grade" class="org.kodejava.spring.core.el.Grade">
        <property name="name">
            <null />
        </property>
        <property name="description" value="A beginner grade." />
    </bean>

</beans>

The use of null-safe accessor can be seen on the student bean’s grade property. We are calling the grade.getName() method and convert it to uppercase. We deliberately set the grade.name property to null. Calling toUpperCase on a null value will throw the NullPointerException. But because we are using the null-safe accessor the exception is not thrown, because the expression will not execute the code after the null-safe accessor. In this case when getName() return null, the toUpperCase() method will never get called.

Below is the demo program code:

package org.kodejava.spring.core.el;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpELNullSafeExpressionDemo {
    public static void main(String[] args) {
        try (ClassPathXmlApplicationContext context =
                     new ClassPathXmlApplicationContext("spel-null-safe.xml")) {

            Student student = (Student) context.getBean("student");
            System.out.println("Name  = " + student.getName());
            System.out.println("Grade = " + student.getGrade());
        }
    }
}

Here is the result of the code:

Name  = Alice
Grade = null

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I inject beans, properties and methods using Spring EL?

Using Spring Expression Language (SpEL) we can inject object references or values into a bean dynamically when the bean is created instead of statically defined at development time. In this example you’ll learn how to inject a bean’s property using a property of another bean.

Let start by create two classes, the Student and Grade classes. The student object will have a property to store their grade name which will be obtained from the grade object.

package org.kodejava.spring.core.el;

public class Student {
    private String name;
    private String grade;

    public Student() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }
}
package org.kodejava.spring.core.el;

public class Grade {
    private String name;
    private String description;

    public Grade() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Next we create the spring configuration file. In this configuration we have two beans definition, the grade and student bean. We set the name and description property of the grade bean.

We also set the name property of student bean using a string literal. But the grade property value is set to the grade‘s bean name property using the Spring EL, #{grade.name}. The expression tells the spring container to look for a bean whose id is grade, read its name and assign it to student‘s grade.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="grade" class="org.kodejava.spring.core.el.Grade">
        <property name="name" value="Beginner" />
        <property name="description" value="A beginner grade." />
    </bean>
    <bean id="student" class="org.kodejava.spring.core.el.Student">
        <property name="name" value="Alice" />
        <property name="grade" value="#{grade.name}" />
    </bean>

</beans>

And then create the following program to execute the spring container and retrieve the student bean from it.

package org.kodejava.spring.core.el;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpELDemo {
    public static void main(String[] args) {
        try (ClassPathXmlApplicationContext context =
                     new ClassPathXmlApplicationContext("spel-example.xml")) {

            Student student = (Student) context.getBean("student");
            System.out.println("Name  = " + student.getName());
            System.out.println("Grade = " + student.getGrade());
        }
    }
}

This program will print the following output:

Name  = Alice
Grade = Beginner

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I use PriorityBlockingQueue class?

This example demonstrate how to use the PriorityBlockingQueue class. The PriorityBlockingQueue is one implementation of the BlockingQueue interface. It is an unbounded concurrent queue. The object place in this type of queue must implement the java.lang.Comparable interface. The Comparable interface defines how the order priority of the elements inside this queue.

For simplicity, in this example we use strings object as the elements to be placed in the queue. The String class implements the comparable interface. Running this example will print out the names in the string array in alphabetical orders.

package org.kodejava.util.concurrent;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;

public class PriorityBlockingQueueExample {
    public static void main(String[] args) {
        final String[] names =
                {"carol", "alice", "malory", "bob", "alex", "jacobs"};

        final BlockingQueue<String> queue = new PriorityBlockingQueue<>();

        new Thread(() -> {
            for (String name : names) {
                try {
                    queue.put(name);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Producer").start();

        new Thread(() -> {
            try {
                for (int i = 0; i < names.length; i++) {
                    System.out.println(queue.take());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Consumer").start();
    }
}

This code print out:

alex
alice
bob
carol
jacobs
malory

How do I use LinkedBlockingQueue class?

In the following code snippet you will learn how to use the LinkedBlockingQueue class. This class implements the BlockingQueue interface. We can create a bounded queue by specifying the queue capacity at the object construction. If we do not define the capacity, the upper bound is limited to the size of Integer.MAX_VALUE.

The data in the queue represented as a linked node in a FIFO (First-In-First-Out) order. The head element of the queue is the longest element placed in the queue and the tail element is the latest element added to the queue.

Let’s see the code in action below:

package org.kodejava.util.concurrent;

import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class LinkedBlockingQueueExample {
    public static void main(String[] args) {
        final BlockingQueue<String> queue = new LinkedBlockingQueue<>(1024);

        // Producer Tread
        new Thread(() -> {
            while (true) {
                try {
                    String data = UUID.randomUUID().toString();
                    System.out.printf("[%s] PUT [%s].%n",
                            Thread.currentThread().getName(), data);
                    queue.put(data);
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Producer").start();

        // Consumer-1 Thread
        new Thread(() -> {
            while (true) {
                try {
                    String data = queue.take();
                    System.out.printf("[%s] GET [%s].%n",
                            Thread.currentThread().getName(), data);
                    Thread.sleep(550);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer-1").start();

        // Consumer-2 Thread
        new Thread(() -> {
            while (true) {
                try {
                    String data = queue.take();
                    System.out.printf("[%s] GET [%s].%n",
                            Thread.currentThread().getName(), data);
                    Thread.sleep(750);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer-2").start();
    }
}

The output of the code snippet above:

[Producer] PUT [34418601-19cf-41fc-aecc-a0fa7caa72bb].
[Consumer-1] GET [34418601-19cf-41fc-aecc-a0fa7caa72bb].
[Producer] PUT [f2050eaa-c575-4faf-89e8-1ad0e3fbce0e].
[Consumer-2] GET [f2050eaa-c575-4faf-89e8-1ad0e3fbce0e].
[Producer] PUT [2f24985b-009b-44c3-9cec-7a066aa08ecf].
[Consumer-1] GET [2f24985b-009b-44c3-9cec-7a066aa08ecf].
[Producer] PUT [b4332823-c1a2-4587-bf5f-1f67407d6945].
[Consumer-2] GET [b4332823-c1a2-4587-bf5f-1f67407d6945].
[Producer] PUT [33edcd78-1b14-4913-afe2-7f44d76db50b].
[Consumer-1] GET [33edcd78-1b14-4913-afe2-7f44d76db50b].

How to implement queue using the DelayQueue?

The java.util.concurrent.DelayQueue class in an implementation of the BlockingQueue interface. Elements added to the queue must implement the java.util.concurrent.Delayed interface.

The queue is unbound in size, enabling adds to return immediately, we can only take an element from the queue when the delay time has expired. If multiple elements have expired delays, the element with the longest delay expiration will be taken first.

package org.kodejava.util.concurrent;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;

public class DelayQueueExample {
    public static void main(String[] args) {
        // Creates an instance of blocking queue using the DelayQueue.
        final BlockingQueue<DelayObject> queue = new DelayQueue<>();
        final Random random = new Random();

        new Thread(() -> {
            while (true) {
                try {
                    // Put some Delayed object into the Queue.
                    int delay = random.nextInt(10000);
                    DelayObject object = new DelayObject(
                            UUID.randomUUID().toString(), delay);

                    System.out.printf("Put object = %s%n", object);
                    queue.put(object);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Producer Thread").start();

        new Thread(() -> {
            while (true) {
                try {
                    // Take elements out from the DelayQueue object.
                    DelayObject object = queue.take();
                    System.out.printf("[%s] - Take object = %s%n",
                            Thread.currentThread().getName(), object);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer Thread-1").start();

        new Thread(() -> {
            while (true) {
                try {
                    // Take elements out from the DelayQueue object.
                    DelayObject object = queue.take();
                    System.out.printf("[%s] - Take object = %s%n",
                            Thread.currentThread().getName(), object);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer Thread-2").start();
    }
}

Below is an implementation of the Delayed interface. In the implementation class we have to implement the getDelay(TimeUnit) and the compareTo(Object) methods.

package org.kodejava.util.concurrent;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class DelayObject implements Delayed {
    private final String data;
    private final long startTime;

    public DelayObject(String data, long delay) {
        this.data = data;
        this.startTime = System.currentTimeMillis() + delay;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        long diff = startTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        return Long.compare(this.startTime, ((DelayObject) o).startTime);
    }

    @Override
    public String toString() {
        return "{" +
                "data='" + data + '\'' +
                ", startTime=" + startTime +
                '}';
    }
}

Running this example give you some kind of the following output:

Put object = {data='ff217d8f-30c7-4ff6-b107-f5e6b13b5cf1', startTime=1635830327667}
Put object = {data='ad9b7f64-04f6-45ba-8b4a-6d9d25785303', startTime=1635830326742}
Put object = {data='7e439219-486a-473f-b093-2ada26b682f4', startTime=1635830328540}
Put object = {data='1fd6f3d2-60b1-4986-a8d0-ceb0863b30a7', startTime=1635830328498}
[Consumer Thread-1] - Take object = {data='ad9b7f64-04f6-45ba-8b4a-6d9d25785303', startTime=1635830326742}
Put object = {data='9d8811a2-5f2a-487b-a229-11ad8ed54515', startTime=1635830330952}
Put object = {data='baf72a83-0242-42cb-93db-9ef08da5f78d', startTime=1635830336088}
[Consumer Thread-2] - Take object = {data='ff217d8f-30c7-4ff6-b107-f5e6b13b5cf1', startTime=1635830327667}
Put object = {data='9d4d14c5-0777-4675-aa67-a49a0519d9b2', startTime=1635830328952}
Put object = {data='c4979d10-4a11-44a8-b79c-ff31309e968b', startTime=1635830331430}

How do I use the ArrayBlockingQueue?

ArrayBlockingQueue is one implementation of the java.util.concurrent.BlockingQueue which internally store the queue elements inside an array. The ArrayBlockingQueue can store elements for the size defined when the object is initialized, by the constructor. Once it size is defined it cannot be change or resize.

The code snippet below demonstrate the ArrayBlockingQueue class. We initialize the queue to allow its internal array to store maximum of 64 elements.

package org.kodejava.util.concurrent;

import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ArrayBlockingQueueExample {
    private final BlockingQueue<String> sharedQueue = new ArrayBlockingQueue<>(64);

    public static void main(String[] args) {
        new ArrayBlockingQueueExample().createProducerConsumer();
    }

    private void createProducerConsumer() {
        new Thread(() -> {
            while (true) {
                System.out.println(Thread.currentThread().getName());
                try {
                    sharedQueue.put("DATA-" + UUID.randomUUID());
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Producer Thread").start();

        new Thread(() -> {
            while (true) {
                System.out.print(Thread.currentThread().getName() + " => ");
                try {
                    System.out.println(sharedQueue.take());
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer Thread-1").start();
    }
}

How do I close or shutdown a BlockingQueue?

In this example you’ll learn how to close or shutdown a BlockingQueue when no more element available in the queue. We will use the common strategy by making the Producer to send a marker object in a Producer – Consumer scenario. This marker object also known as the poison object will be considered as a sign that the queue contain no more object that need to be processed. Which then will allow us to break the operation of the consumer thread.

package org.kodejava.util.concurrent;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueShutdown {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(32);

        MyDataProducer producer = new MyDataProducer(queue);
        MyDataConsumer consumer = new MyDataConsumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

Below is the Producer object that put data into the queue. The string DONE is our marker object. This is the last data will be placed in the queue for the consumer to pick up.

package org.kodejava.util.concurrent;

import java.util.concurrent.BlockingQueue;

public class MyDataProducer implements Runnable {
    BlockingQueue<String> queue;

    public MyDataProducer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("MyDataProducer.run");
        String[] data = {"D001", "D002", "D003", "D004", "D005", "DONE"};

        try {
            for (String element : data) {
                queue.put(element);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

The Consumer object loops to retrieve elements from the queue. And it will break the loop and ended the thread when it receives the marker object from the queue.

package org.kodejava.util.concurrent;

import java.util.concurrent.BlockingQueue;

public class MyDataConsumer implements Runnable {
    BlockingQueue<String> queue;

    public MyDataConsumer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("MyDataConsumer.run");

        while (true) {
            try {
                String element = queue.take();
                if ("DONE".equals(element)) {
                    System.out.println("Exiting consumer thread, " +
                            "end of data reached.");
                    break;
                }
                System.out.println("Element = " + element);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}