之前博客写了篇博文,面试时要求使用多线程顺序打印ABC循环20次,这是我当时使用join函数实现代码:
public class TestABCJoin {public static void main(String[] args) {// 创建任务Runnable taskA = () -> {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}};Runnable taskB = () -> {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}};Runnable taskC = () -> {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}};// 循环 20 次for (int i = 0; i < 20; i++) {Thread threadA = new Thread(taskA, "A");Thread threadB = new Thread(taskB, "B");Thread threadC = new Thread(taskC, "C");try {threadA.start(); // 启动 AthreadA.join(); // 等待 A 执行完毕threadB.start(); // 启动 BthreadB.join(); // 等待 B 执行完毕threadC.start(); // 启动 CthreadC.join(); // 等待 C 执行完毕} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}
}
这两天复习多线程,想到condition也可以实现这个需求,先贴上代码:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class TestABCLockCondition {public static void main(String[] args) {Alternate alternate = new Alternate();new Thread(() -> {for (int i = 0; i < 20; i++) {alternate.loopA(i);}}, "A").start();new Thread(() -> {for (int i = 0; i < 20; i++) {alternate.loopB(i);}}, "B").start();new Thread(() -> {for (int i = 0; i < 20; i++) {alternate.loopC(i);}}, "C").start();}
}class Alternate {private int number = 1; // 当前应执行的线程标记:1-A, 2-B, 3-Cprivate final Lock lock = new ReentrantLock();private final Condition conditionA = lock.newCondition();private final Condition conditionB = lock.newCondition();private final Condition conditionC = lock.newCondition();public void loopA(int totalLoop) {lock.lock();try {while (number != 1) {conditionA.await();}for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);}number = 2;conditionB.signal();} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {lock.unlock();}}public void loopB(int totalLoop) {lock.lock();try {while (number != 2) {conditionB.await();}for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);}number = 3;conditionC.signal();} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {lock.unlock();}}public void loopC(int totalLoop) {lock.lock();try {while (number != 3) {conditionC.await();}for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);}number = 1;conditionA.signal();} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {lock.unlock();}}
}
思考了下这两种方案的优缺点(deepseek总结):
使用 join() 实现顺序打印是一种简单直观的方式,适合小规模任务。但对于高并发场景,建议使用更高效的同步机制(如 ReentrantLock 和 Condition)。
好奇具体是为什么:
可以发现,第一种方法每次循环都需要创建新的线程(new Thread()),并在任务完成后销毁线程。我们知道线程的创建和销毁是非常昂贵的操作,尤其是在高并发场景下,频繁创建线程会导致性能急剧下降。
同时join() 会阻塞当前线程(通常是主线程),直到目标线程执行完毕。
使用信号量在高并发场景下的优势:
Condition 提供了 await() 和 signal() 方法,可以精确控制线程的等待和唤醒。
ReentrantLock 和 Condition 可以实现非阻塞的线程协作,避免主线程被阻塞。