题目
使用两个线程交替打印奇偶数
信息
- 类型:问答
- 难度:⭐
考点
线程创建,线程同步,线程间通信
快速回答
实现两个线程交替打印奇偶数的核心要点:
- 创建两个线程分别处理奇数和偶数打印
- 使用
synchronized关键字实现线程同步 - 通过
wait()和notify()实现线程间通信 - 共享计数器变量控制打印范围
原理说明
该题目考察多线程协作的基本原理:
1. 两个线程共享一个计数器变量
2. 通过synchronized锁定共享对象保证原子性
3. 使用wait()让当前线程释放锁并等待
4. 使用notify()唤醒等待线程继续执行
代码示例
public class AlternatePrinting {
private static final Object lock = new Object();
private static int count = 1;
private static final int MAX = 10;
public static void main(String[] args) {
// 奇数线程
new Thread(() -> {
synchronized (lock) {
while (count <= MAX) {
if (count % 2 == 1) {
System.out.println("奇数线程: " + count++);
lock.notify(); // 唤醒偶数线程
} else {
try {
lock.wait(); // 释放锁等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
// 偶数线程
new Thread(() -> {
synchronized (lock) {
while (count <= MAX) {
if (count % 2 == 0) {
System.out.println("偶数线程: " + count++);
lock.notify(); // 唤醒奇数线程
} else {
try {
lock.wait(); // 释放锁等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
}最佳实践
- 使用专用锁对象(如
private static final Object lock)而非this - 循环检查条件(
while代替if)防止虚假唤醒 - 明确限定共享变量的操作范围(如
count仅在同步块内访问) - 添加终止条件(
count <= MAX)避免无限循环
常见错误
- 忘记唤醒:执行后未调用
notify()导致线程永久等待 - 错误锁对象:在
wait()/notify()中使用不同锁对象 - 条件判断缺陷:使用
if判断条件可能引发虚假唤醒问题 - 同步范围过大:将整个
run()方法同步导致性能下降
扩展知识
- Lock/Condition:Java 5+可使用
ReentrantLock和Condition实现更灵活的线程通信 - volatile变量:保证共享变量的可见性(但无法保证复合操作原子性)
- 线程状态:
wait()会使线程进入WAITING状态,notify()将其唤醒为BLOCKED状态 - 生产消费者模式:本题是生产者消费者模式的简化变种,核心思想相同