在并发编程中,阻塞队列是一种常见的数据结构,它支持多线程间安全的数据交换。本文将介绍如何使用 Java 中的 wait
和 notify
方法来实现一个简单的阻塞队列。
目录
队列结构与设计
我们将实现一个基于 LinkedList
的简单阻塞队列,具有固定的长度限制。队列中的元素类型为整数。
类成员
private static Queue<Integer> queue = new LinkedList<>(); // 使用 LinkedList 作为队列实现
private static final int LENGTH = 5; // 队列长度限制
private static Random random = new Random(); // 用于生成随机数
private static Object lock = new Object(); // 用于同步的锁对象
插入元素方法 queueInsert()
public static void queueInsert() {
synchronized (lock) {
while (queue.size() >= LENGTH) {
try {
System.out.println("队列已满,等待空间");
lock.wait(); // 队列已满,等待空间释放
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生成随机数作为新元素
int index = random.nextInt(10);
queue.offer(index); // 将新元素添加到队列尾部
System.out.println("队列添加数据:" + index);
lock.notifyAll(); // 唤醒所有等待线程
}
}
移除元素方法 queueRemove()
public static void queueRemove() {
synchronized (lock) {
while (queue.isEmpty()) {
try {
System.out.println("队列为空,等待数据");
lock.wait(); // 队列为空,等待数据可用
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int index = queue.remove(); // 移除队首元素
System.out.println(index + "被移除");
lock.notifyAll(); // 唤醒所有等待线程
}
}
主程序及线程运行
在 main
方法中启动两个线程,一个负责插入元素,一个负责移除元素:
public static void main(String[] args) {
Thread threadInsert = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
queueInsert();
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread threadRemove = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
queueRemove();
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
threadInsert.start();
threadRemove.start();
}
实现思路解析
- 同步机制: 使用
synchronized
关键字和一个共享的lock
对象来保证线程安全。 - 等待和唤醒: 在队列已满或为空时,使用
lock.wait()
让当前线程进入等待状态,直到被lock.notifyAll()
唤醒。 - 线程操作:
queueInsert()
负责向队列中添加元素,当队列已满时等待空闲空间;queueRemove()
负责从队列中移除元素,当队列为空时等待数据可用。 - 随机等待时间: 为了模拟真实场景,每个操作都会随机等待一段时间。
总结
通过以上实现,我们成功创建了一个简单的阻塞队列,并使用 wait
和 notify
方法实现了线程间的协作。这种设计能有效地避免常见的并发问题,如数据竞争和死锁,提升了程序的可靠性和稳定性。
在实际应用中,Java 的并发包 java.util.concurrent
提供了更高级的并发数据结构,如 BlockingQueue
,它们已经封装了底层的并发控制机制,能够更方便地处理多线程情况下的数据交换操作。