学过数据结构的都应该知道,队列是什么,并且应该都知道队列最重要的特点是什么,实际上在Java中也是一样的,遵循这样的特点的,Java中的队列可以通过Java,util.Queue接口来实现,常见的队列实现包括java.util.linkedList和java.util.ArrayDeque。
Queue
队列的特点:
- 先进先出: 队列遵循先进先出的原则,即先进入队列的元素将首先被移除。
- 添加和移除操作: 队列提供了添加和移除元素的操作,通常使用
offer()
方法将元素添加到队列的尾部,使用poll()
方法移除队列头部的元素。 - 头部元素访问: 可以使用
peek()
方法获取队列头部的元素,而不会将其队列移除。 - 队列大小: 可以使用size()方法获取队列中元素的数量。
- 队列为空:可以使用isEmpty()方法检查队列是否为空。
- 变量队列:可以使用迭代循环或者迭代器遍历队列中的元素。
- 阻塞队列: java还提供特殊的队列实现,例如:java,util.concurrent.blockingQueue接口的实现类,用于多线程下的并发操作,这些队列提供了阻塞操作,可以在队列为空或者队列已满的时候阻塞队列。
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
// 添加元素到队列
queue.offer("Apple");
queue.offer("Banana");
queue.offer("Orange");
// 获取队列头部元素
String head = queue.peek();
System.out.println("队列头部元素:" + head);
// 移除队列头部元素
String removedElement = queue.poll();
System.out.println("移除的元素:" + removedElement);
// 遍历队列中的元素
System.out.println("队列中的元素:");
for (String element : queue) {
System.out.println(element);
}
}
BlockingQueue
BlockingQueue是一个接口,它扩展了Queue接口,并提供了在队列为空或队列已满时阻塞线程的功能。BlockingQueue用于多线程环境下的并发操作,可以安全地在多个线程之间传递数据。
- put(E element): 将元素添加到队列的尾部,如果队列已满,则阻塞线程直到队列有空间可用。
- take(): 移除并返回队列头部的元素,如果队列为空,则阻塞线程直到队列有元素可用。
- offer(E element, long timeout, TimeUnit unit): 将元素添加到队列的尾部,如果队列已满,则阻塞线程一段时间,超时后返回特定的结果。
- poll(long timeout, TimeUnit unit): 移除并返回队列头部的元素,如果队列为空,则阻塞线程一段时间,超时后返回特定的结果。
- size(): 返回队列中的元素数量。
- 不接受null元素试图调用add,put,或者offer一个null元素时,某些实现会抛出NullPointerException。
BlockingQueue接口的常见实现类包括:
- ArrayBlockingQueue: 基于数组的有界阻塞队列。
- LinkedBlockingQueue: 基于链表的可选有界或无界阻塞队列。
- PriorityBlockingQueue: 基于优先级的无界阻塞队列。
- SynchronousQueue: 一个不存储元素的阻塞队列,用于线程间直接传递数据。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class BlockingQueueExample {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(3);
// 生产者线程
Thread producerThread = new Thread(() -> {
try {
queue.put("Apple");
queue.put("Banana");
queue.put("Orange");
System.out.println("生产者线程已添加元素到队列");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 消费者线程
Thread consumerThread = new Thread(() -> {
try {
Thread.sleep(2000); // 模拟消费者处理时间
String element = queue.take();
System.out.println("消费者线程已移除元素:" + element);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producerThread.start();
consumerThread.start();
}
}
这个示例代码创建了一个LinkedBlockingQueue实例,设置队列的容量为3。然后,一个生产者线程向队列中添加3个元素,一个消费者线程从队列中移除一个元素。由于队列是阻塞的,消费者线程会等待生产者线程添加元素后再执行。
AbstractQueue
AbstractQueue是一个抽象类,它实现了Queue接口的大部分方法,并提供了一些默认的实现。AbstractQueue为具体的队列实现类提供了一些通用的行为和方法。
- add(E element): 将元素添加到队列的尾部,如果队列已满,则抛出异常。
- offer(E element): 将元素添加到队列的尾部,如果队列已满,则返回false。
- remove(): 移除并返回队列头部的元素,如果队列为空,则抛出异常。
- poll(): 移除并返回队列头部的元素,如果队列为空,则返回null。
- element(): 返回队列头部的元素,如果队列为空,则抛出异常。
- peek(): 返回队列头部的元素,如果队列为空,则返回null。
- isEmpty(): 检查队列是否为空。
- size(): 返回队列中的元素数量。
import java.util.AbstractQueue;
import java.util.Iterator;
import java.util.LinkedList;
public class CustomQueue<E> extends AbstractQueue<E> {
private LinkedList<E> queue = new LinkedList<>();
@Override
public boolean offer(E element) {
return queue.offer(element);
}
@Override
public E poll() {
return queue.poll();
}
@Override
public E peek() {
return queue.peek();
}
@Override
public Iterator<E> iterator() {
return queue.iterator();
}
@Override
public int size() {
return queue.size();
}
public static void main(String[] args) {
CustomQueue<String> queue = new CustomQueue<>();
queue.offer("Apple");
queue.offer("Banana");
queue.offer("Orange");
System.out.println("队列大小:" + queue.size());
System.out.println("队列头部元素:" + queue.peek());
System.out.println("遍历队列:");
for (String element : queue) {
System.out.println(element);
}
}
}
使用AbstractQueue来实现一个简单的任务调度器
import java.util.AbstractQueue;
import java.util.Iterator;
import java.util.concurrent.PriorityBlockingQueue;
public class TaskScheduler extends AbstractQueue<Task> {
private PriorityBlockingQueue<Task> taskQueue = new PriorityBlockingQueue<>();
@Override
public boolean offer(Task task) {
return taskQueue.offer(task);
}
@Override
public Task poll() {
return taskQueue.poll();
}
@Override
public Task peek() {
return taskQueue.peek();
}
@Override
public Iterator<Task> iterator() {
return taskQueue.iterator();
}
@Override
public int size() {
return taskQueue.size();
}
public static void main(String[] args) {
TaskScheduler scheduler = new TaskScheduler();
// 添加任务到调度器
scheduler.offer(new Task("Task 1", 3));
scheduler.offer(new Task("Task 2", 1));
scheduler.offer(new Task("Task 3", 2));
// 执行任务
while (!scheduler.isEmpty()) {
Task task = scheduler.poll();
System.out.println("执行任务:" + task.getName());
// 模拟任务执行时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Task implements Comparable<Task> {
private String name;
private int priority;
public Task(String name, int priority) {
this.name = name;
this.priority = priority;
}
public String getName() {
return name;
}
public int getPriority() {
return priority;
}
@Override
public int compareTo(Task other) {
return Integer.compare(this.priority, other.priority);
}
}
我们创建了一个TaskScheduler类,它继承了AbstractQueue类,并使用PriorityBlockingQueue作为内部的任务队列。Task类表示一个任务,它实现了Comparable接口,以便根据优先级进行排序。
在main方法中,我们创建了一个TaskScheduler实例,并添加了三个具有不同优先级的任务。然后,我们通过循环从调度器中取出任务并执行,模拟了任务调度的过程。