Types of BlockingQueue in Java Concurrency with Examples

Here’s a breakdown of the differences between ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, and DelayQueue in Java, along with examples for each:

1. ArrayBlockingQueue

  • Description: A bounded blocking queue backed by an array. It stores elements in a FIFO (first-in-first-out) order. When the queue is full, the producer will block until space becomes available.
  • Use Case: Best for scenarios with a known, fixed number of elements, where you need a bounded queue with efficient memory usage.

Example:

import java.util.concurrent.ArrayBlockingQueue;

public class ArrayBlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3); // Capacity of 3

        // Producer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("Producing: " + i);
                    queue.put(i); // Blocks if queue is full
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // Consumer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    Integer value = queue.take(); // Blocks if queue is empty
                    System.out.println("Consuming: " + value);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

2. LinkedBlockingQueue

  • Description: A blocking queue backed by a linked node structure. It can be optionally bounded or unbounded. It allows for high throughput by permitting multiple producers and consumers.
  • Use Case: Ideal for scenarios requiring high concurrency and where the maximum capacity is unknown or not critical.

Example:

import java.util.concurrent.LinkedBlockingQueue;

public class LinkedBlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        LinkedBlockingQueue queue = new LinkedBlockingQueue<>(5); // Bounded capacity of 5

        // Producer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    System.out.println("Producing: " + i);
                    queue.put(i); // Blocks if queue is full
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // Consumer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    Integer value = queue.take(); // Blocks if queue is empty
                    System.out.println("Consuming: " + value);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

3. PriorityBlockingQueue

  • Description: An unbounded blocking queue that orders its elements according to their natural ordering or by a specified comparator. It does not guarantee FIFO order.
  • Use Case: Useful when you want to prioritize certain tasks over others, such as in scheduling applications.

Example:

import java.util.concurrent.PriorityBlockingQueue;

public class PriorityBlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        PriorityBlockingQueue queue = new PriorityBlockingQueue<>();

        // Producer
        new Thread(() -> {
            try {
                for (int i = 5; i >= 1; i--) {
                    System.out.println("Producing Task with Priority: " + i);
                    queue.put(new Task(i)); // Higher priority (lower number) will be taken first
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // Consumer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    Task task = queue.take(); // Blocks if queue is empty
                    System.out.println("Consuming Task with Priority: " + task.priority);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }

    static class Task implements Comparable {
        int priority;

        Task(int priority) {
            this.priority = priority;
        }

        @Override
        public int compareTo(Task o) {
            return Integer.compare(this.priority, o.priority); // Lower priority number is "greater"
        }
    }
}

4. DelayQueue

  • Description: A specialized blocking queue that holds elements until they become eligible for processing based on a specified delay. It does not allow null elements.
  • Use Case: Useful for scheduling tasks that need to wait for a certain time before they can be processed.

Example:

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

public class DelayQueueExample {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue queue = new DelayQueue<>();

        // Producer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    DelayedTask task = new DelayedTask("Task " + i, i * 1000);
                    System.out.println("Producing: " + task.name);
                    queue.put(task); // Adds the task to the delay queue
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // Consumer
        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    DelayedTask task = queue.take(); // Blocks until a task is available
                    System.out.println("Consuming: " + task.name + " after delay");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }

    static class DelayedTask implements Delayed {
        String name;
        long delay;

        DelayedTask(String name, long delay) {
            this.name = name;
            this.delay = System.currentTimeMillis() + delay;
        }

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

        @Override
        public int compareTo(Delayed o) {
            if (this.delay < ((DelayedTask) o).delay) return -1;
            if (this.delay > ((DelayedTask) o).delay) return 1;
            return 0;
        }
    }
}

Summary of Differences

FeatureArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueueDelayQueue
Backing StructureArrayLinked nodesHeap-basedInternal Priority Queue
BoundedYesYes (or unbounded)NoNo
OrderingFIFOFIFOPriority-basedBased on delay
Use CaseFixed-size producer-consumerHigh concurrencyTask prioritizationScheduled task processing

These examples and explanations should help clarify the differences between these BlockingQueue implementations and how to use them effectively in concurrent programming in Java.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *