题目描述​

编写一个 Java 程序,创建 3 个线程,分别负责打印字符 A、B、C,要求 3 个线程协同工作,按 “A→B→C” 的顺序循环打印 10 次,最终输出结果为 “ABCABCABC...ABC”(共 30 个字符,循环 10 轮)。​

核心要求:​

  1. 严格保证打印顺序,不可出现 “ABA”“ACB” 等乱序情况;​
  1. 线程间需协调同步,避免资源竞争导致的打印混乱;​
  1. 循环结束后,所有线程需正常终止,无资源泄漏。​

解题思路​

多线程交替打印的核心是 “线程间的有序通信”—— 每个线程打印完成后,需通知下一个线程开始打印,同时自身进入等待状态。常见两种实现方案:​

  1. 基于 ReentrantLock+Condition:利用 Lock 锁保证临界区互斥,通过 Condition 的await()/signal()实现线程间精准唤醒,灵活性高;​
  1. 基于 Object 的 wait ()/notify ():利用 Java 原生的对象监视器锁(synchronized),通过wait()让线程等待,notify()唤醒指定线程,无需额外引入 Lock 类。​

两种方案均需维护一个 “当前应打印的字符标识”,线程打印前需检查标识是否匹配,不匹配则等待,匹配则打印并更新标识,再唤醒下一个线程。

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.ReentrantLock;

// 打印控制器:封装锁、条件变量与打印状态

class PrintController {

// 锁对象:保证打印操作的互斥性

private final ReentrantLock lock = new ReentrantLock();

// 3个条件变量:分别对应A、B、C线程的等待/唤醒

private final Condition conditionA = lock.newCondition();

private final Condition conditionB = lock.newCondition();

private final Condition conditionC = lock.newCondition();

// 当前应打印的字符(初始为'A',表示第一个打印A)

private char currentChar = 'A';

// 已完成的打印轮次(控制循环10次)

private int round = 0;

// A线程的打印方法

public void printA() throws InterruptedException {

// 加锁:进入临界区,确保线程安全

lock.lock();

try {

// 循环检查:若当前不应打印A,或已完成10轮,则A线程等待

while (currentChar != 'A' || round >= 10) {

conditionA.await(); // A线程进入等待,释放锁

}

// 打印逻辑:输出A

System.out.print("A");

// 更新状态:下一个应打印B,完成1轮(每打印C后才算1轮,此处仅标记A完成)

currentChar = 'B';

// 唤醒B线程:通知B可以开始打印

conditionB.signal();

} finally {

// 解锁:无论是否发生异常,都需释放锁,避免死锁

lock.unlock();

}

}

// B线程的打印方法(逻辑与A类似)

public void printB() throws InterruptedException {

lock.lock();

try {

while (currentChar != 'B' || round >= 10) {

conditionB.await();

}

System.out.print("B");

currentChar = 'C'; // 下一个应打印C

conditionC.signal(); // 唤醒C线程

} finally {

lock.unlock();

}

}

// C线程的打印方法(需额外处理轮次计数)

public void printC() throws InterruptedException {

lock.lock();

try {

while (currentChar != 'C' || round >= 10) {

conditionC.await();

}

System.out.print("C");

currentChar = 'A'; // 下一轮重新从A开始

round++; // 每打印完C,代表1轮完成,轮次+1

// 唤醒A线程:通知下一轮A可以开始打印

conditionA.signal();

} finally {

lock.unlock();

}

}

}

// 线程任务:实现Runnable,封装具体打印逻辑

class PrintTask implements Runnable {

private final PrintController controller;

private final char taskChar; // 当前任务需打印的字符(A/B/C)

public PrintTask(PrintController controller, char taskChar) {

this.controller = controller;

this.taskChar = taskChar;

}

@Override

public void run() {

try {

// 循环打印:直到完成10轮(round >= 10时,打印方法会等待,需退出循环)

while (controller.round < 10) {

// 根据任务字符调用对应打印方法

switch (taskChar) {

case 'A':

controller.printA();

break;

case 'B':

controller.printB();

break;

case 'C':

controller.printC();

break;

}

// 轻微休眠:避免线程过度抢占CPU(可选,不影响正确性)

Thread.sleep(10);

}

} catch (InterruptedException e) {

// 捕获中断异常,恢复线程中断状态(规范操作)

Thread.currentThread().interrupt();

}

}

}

// 测试类:创建线程并启动

public class AlternatePrintABC {

public static void main(String[] args) {

// 1. 创建打印控制器(共享资源)

PrintController controller = new PrintController();

// 2. 创建3个线程,分别绑定A、B、C打印任务

Thread threadA = new Thread(new PrintTask(controller, 'A'), "Thread-A");

Thread threadB = new Thread(new PrintTask(controller, 'B'), "Thread-B");

Thread threadC = new Thread(new PrintTask(controller, 'C'), "Thread-C");

// 3. 启动线程(启动顺序不影响最终打印顺序,因控制器会控制等待/唤醒)

threadA.start();

threadB.start();

threadC.start();

// 4. 主线程等待子线程结束(可选,确保程序完整执行)

try {

threadA.join();

threadB.join();

threadC.join();

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

System.out.println("\n10轮打印完成!");

}

}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐