两个线程交替打印 0~100 奇偶数¶
结论¶
用 synchronized + wait/notify 或 Lock + Condition 都能实现。核心是两个线程共享一个状态变量,通过等待/唤醒切换执行权。
方法一:synchronized + wait/notify¶
public class AlternatePrint {
private static int num = 0;
private static final Object LOCK = new Object();
public static void main(String[] args) {
// 偶数线程
new Thread(() -> {
while (num <= 100) {
synchronized (LOCK) {
if (num % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ": " + num++);
LOCK.notify();
} else {
try { LOCK.wait(); } catch (InterruptedException ignored) {}
}
}
}
}, "偶数").start();
// 奇数线程
new Thread(() -> {
while (num <= 100) {
synchronized (LOCK) {
if (num % 2 == 1) {
System.out.println(Thread.currentThread().getName() + ": " + num++);
LOCK.notify();
} else {
try { LOCK.wait(); } catch (InterruptedException ignored) {}
}
}
}
}, "奇数").start();
}
}
必须用 while 而不是 if
wait() 被唤醒后需要重新检查条件,防止"虚假唤醒"(spurious wakeup)。这是 JDK Object.wait() 文档的明确建议。
方法二:Lock + Condition(更清晰)¶
Lock lock = new ReentrantLock();
Condition even = lock.newCondition();
Condition odd = lock.newCondition();
// 偶数线程
lock.lock();
try {
while (num % 2 != 0) even.await();
System.out.println("偶数: " + num++);
odd.signal();
} finally { lock.unlock(); }
方法三:两个线程用 TransferQueue / Exchanger¶
更现代的写法是用 Exchanger<Integer>,但题面要求"两个线程",wait/notify 最经典。
方法四:Semaphore¶
Semaphore semEven = new Semaphore(1);
Semaphore semOdd = new Semaphore(0);
// 偶数线程
semEven.acquire();
System.out.println(num++);
semOdd.release();
面试加分
- 答出
wait必须在 synchronized 块内、会释放锁。 - 答出
notify只是唤醒,不释放锁(要等 synchronized 块结束才释放)。 - 推荐用
Condition替代,因为可以精确唤醒特定线程,避免"惊群"。