Java LinkedBlockingQueue
In Java, managing data between multiple threads can be challenging, especially when synchronization is required. One of the key utilities provided by the java.util.concurrent
package is the LinkedBlockingQueue
class. It is an implementation of the BlockingQueue
interface that uses a linked-node structure to store elements. Unlike ArrayBlockingQueue
, which has a fixed size, LinkedBlockingQueue
can be either bounded (with a fixed capacity) or unbounded, making it a versatile choice for many concurrent programming tasks.
The LinkedBlockingQueue
is a thread-safe queue used for managing data in concurrent applications. It implements the BlockingQueue
interface, which offers blocking operations like put()
and take()
, enabling threads to safely interact with the queue without the risk of race conditions.
The key characteristic of LinkedBlockingQueue
is that it can be either bounded or unbounded:
Key features:
LinkedBlockingQueue
are thread-safe.put()
and take()
, ideal for managing resources between threads.You can create a LinkedBlockingQueue
with the following constructors:
LinkedBlockingQueue(int capacity) // Creates a bounded queue with the specified capacity
LinkedBlockingQueue() // Creates an unbounded queue
LinkedBlockingQueue(int capacity, boolean fair) // Creates a bounded queue with a fairness policy
true
, the queue will guarantee FIFO order, ensuring that threads acquire resources in the order they requested them.LinkedBlockingQueue
provides several key methods for inserting, removing, and inspecting elements in the queue:
false
if the queue is full.null
if the queue is empty.Here is a simple example of how to use a LinkedBlockingQueue
in a producer-consumer scenario.
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
public static void main(String[] args) throws InterruptedException {
// Create a LinkedBlockingQueue with a capacity of 2
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(2);
// Producer thread
Thread producer = new Thread(() -> {
try {
// Add items to the queue
System.out.println("Producer: Adding item 1");
queue.put("Item 1");
System.out.println("Producer: Adding item 2");
queue.put("Item 2");
System.out.println("Producer: Adding item 3");
queue.put("Item 3"); // This will block as the queue is full
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Consumer thread
Thread consumer = new Thread(() -> {
try {
// Remove items from the queue
System.out.println("Consumer: Removing " + queue.take());
System.out.println("Consumer: Removing " + queue.take());
System.out.println("Consumer: Removing " + queue.take());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
Output:
Producer: Adding item 1
Producer: Adding item 2
Consumer: Removing Item 1
Producer: Adding item 3
Consumer: Removing Item 2
Consumer: Removing Item 3
In this example:
LinkedBlockingQueue
. It blocks when attempting to add the third item because the queue is full (capacity is 2).If you don’t specify a capacity, the LinkedBlockingQueue
becomes unbounded and can grow indefinitely. Here's an example:
import java.util.concurrent.LinkedBlockingQueue;
public class UnboundedQueueExample {
public static void main(String[] args) throws InterruptedException {
// Create an unbounded LinkedBlockingQueue
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
// Producer thread
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
System.out.println("Producer: Adding item " + i);
queue.put("Item " + i); // No blocking, queue is unbounded
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Consumer thread
Thread consumer = new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
System.out.println("Consumer: Removing " + queue.take());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
Output:
Producer: Adding item 1
Consumer: Removing Item 1
Producer: Adding item 2
Consumer: Removing Item 2
Producer: Adding item 3
Consumer: Removing Item 3
Producer: Adding item 4
Consumer: Removing Item 4
Producer: Adding item 5
Consumer: Removing Item 5
In this case, the LinkedBlockingQueue
grows as needed, and the producer can add items without being blocked, while the consumer consumes them as they arrive.
You can also create a LinkedBlockingQueue
with a fairness policy, ensuring that threads are served in the order they requested access. Here’s an example of using the fairness parameter:
import java.util.concurrent.LinkedBlockingQueue;
public class FairQueueExample {
public static void main(String[] args) throws InterruptedException {
// Create a fair LinkedBlockingQueue with a capacity of 2
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(2, true);
// Producer thread
Thread producer = new Thread(() -> {
try {
System.out.println("Producer: Adding item 1");
queue.put("Item 1");
System.out.println("Producer: Adding item 2");
queue.put("Item 2");
System.out.println("Producer: Adding item 3");
queue.put("Item 3"); // This will block as the queue is full
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Consumer threads
Thread consumer1 = new Thread(() -> {
try {
System.out.println("Consumer 1: Removing " + queue.take());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread consumer2 = new Thread(() -> {
try {
System.out.println("Consumer 2: Removing " + queue.take());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
consumer1.start();
consumer2.start();
producer.start();
producer.join();
consumer1.join();
consumer2.join();
}
}
Output:
Producer: Adding item 1
Producer: Adding item 2
Consumer 1: Removing Item 1
Producer: Adding item 3
Consumer 2: Removing Item 2
In this case, because fairness is enabled, consumer 1 is served before consumer 2, even though they both started at roughly the same time.
The LinkedBlockingQueue
is a great choice for:
LinkedBlockingQueue
provides the necessary blocking mechanism.LinkedBlockingQueue
can be very useful.