方式1:使用synchronized和wait()/notify()
java
public class AlternatePrint {
private int number = 1;
private final Object lock = new Object();
public void printOddEven() {
// 奇数线程
Thread thread1 = new Thread(() -> {
synchronized (lock) {
while (number <= 100) {
if (number % 2 == 1) { // 打印奇数
System.out.println(Thread.currentThread().getName() + ": " + number++);
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
lock.notify(); // 唤醒可能还在等待的线程
}
}, "奇数线程");
// 偶数线程
Thread thread2 = new Thread(() -> {
synchronized (lock) {
while (number <= 100) {
if (number % 2 == 0) { // 打印偶数
System.out.println(Thread.currentThread().getName() + ": " + number++);
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
lock.notify(); // 唤醒可能还在等待的线程
}
}, "偶数线程");
thread1.start();
thread2.start();
}
public static void main(String[] args) {
new AlternatePrint().printOddEven();
}
}
方式2:使用ReentrantLock和Condition(更灵活)
java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class AlternatePrintWithLock {
private int number = 1;
private final ReentrantLock lock = new ReentrantLock();
private final Condition oddCondition = lock.newCondition(); // 奇数条件
private final Condition evenCondition = lock.newCondition(); // 偶数条件
public void printOddEven() {
// 打印奇数
Thread oddThread = new Thread(() -> {
lock.lock();
try {
while (number <= 100) {
if (number % 2 == 1) {
System.out.println("奇数线程: " + number++);
evenCondition.signal(); // 唤醒偶数线程
} else {
oddCondition.await(); // 等待
}
}
evenCondition.signal(); // 最后唤醒偶数线程,防止死锁
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
// 打印偶数
Thread evenThread = new Thread(() -> {
lock.lock();
try {
while (number <= 100) {
if (number % 2 == 0) {
System.out.println("偶数线程: " + number++);
oddCondition.signal(); // 唤醒奇数线程
} else {
evenCondition.await(); // 等待
}
}
oddCondition.signal(); // 最后唤醒奇数线程,防止死锁
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
oddThread.start();
evenThread.start();
}
public static void main(String[] args) {
new AlternatePrintWithLock().printOddEven();
}
}
方式3:使用AtomicInteger和Semaphore(更简洁)
java
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
public class AlternatePrintWithSemaphore {
private AtomicInteger number = new AtomicInteger(1);
private Semaphore oddSemaphore = new Semaphore(1); // 奇数信号量,初始有许可
private Semaphore evenSemaphore = new Semaphore(0); // 偶数信号量,初始无许可
public void printOddEven() {
// 打印奇数
Thread oddThread = new Thread(() -> {
while (number.get() <= 100) {
try {
oddSemaphore.acquire(); // 获取奇数信号量
if (number.get() <= 100) {
System.out.println("奇数线程: " + number.getAndIncrement());
}
evenSemaphore.release(); // 释放偶数信号量
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 打印偶数
Thread evenThread = new Thread(() -> {
while (number.get() <= 100) {
try {
evenSemaphore.acquire(); // 获取偶数信号量
if (number.get() <= 100) {
System.out.println("偶数线程: " + number.getAndIncrement());
}
oddSemaphore.release(); // 释放奇数信号量
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
oddThread.start();
evenThread.start();
}
public static void main(String[] args) {
new AlternatePrintWithSemaphore().printOddEven();
}
}
方式4:通用模板类(可复用)
java
public class AlternatePrintTemplate {
private int num = 1;
private final Object lock = new Object();
public void alternatePrint(int max) {
new Thread(() -> printNum(max, 1), "线程A").start();
new Thread(() -> printNum(max, 0), "线程B").start();
}
private void printNum(int max, int remainder) {
synchronized (lock) {
while (num <= max) {
// 使用位运算判断奇偶,性能更好
if ((num & 1) == remainder) {
System.out.println(Thread.currentThread().getName() + ": " + num++);
lock.notifyAll();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
public static void main(String[] args) {
new AlternatePrintTemplate().alternatePrint(100);
}
}
关键点说明:
-
线程同步:必须确保两个线程不会同时操作共享变量
-
线程通信:需要正确使用wait/notify或Condition进行线程间通信
-
边界条件:正确处理打印到100后两个线程都能正常退出
-
避免死锁:确保即使一个线程先结束,另一个线程也不会永久等待
推荐:
-
对于简单场景,推荐使用方式1(synchronized)
-
对于需要更精细控制的情况,推荐方式2(ReentrantLock)
-
对于性能要求高的场景,推荐使用方式4的位运算判断奇偶
这些方法都能实现两个线程交替打印1-100,输出结果类似于:
java
奇数线程: 1
偶数线程: 2
奇数线程: 3
偶数线程: 4
...
奇数线程: 99
偶数线程: 100