当前位置: 首页 > news >正文

美橙互联网站淘宝店铺网站建设

美橙互联网站,淘宝店铺网站建设,电子商务网站建设的基本步骤,制作网站建设拓扑图软件前言 最近笔者在面试过程中被问到如何实现线程轮流打印 ABC,当时没想到,基础太差,故作此文 Java 多线程轮流打印 ABC 的 4 种实现方式详解 在多线程编程中,一个经典的面试题是: 启动三个线程,分别打印 A、B、C&#x…

前言

最近笔者在面试过程中被问到如何实现线程轮流打印 ABC,当时没想到,基础太差,故作此文

Java 多线程轮流打印 ABC 的 4 种实现方式详解

在多线程编程中,一个经典的面试题是:

启动三个线程,分别打印 A、B、C,要求按顺序轮流输出,如 ABCABCABC… 重复若干次。

这个问题看似简单,但涉及线程间的协作与通信。本文将从入门到进阶,系统讲解 4 种主流解法,并附带完整可运行的源码。


💡 实现目标

假设每个线程负责打印一个字符:

  • 线程 A 打印 A
  • 线程 B 打印 B
  • 线程 C 打印 C

期望输出如下格式:

ABCABCABCABCABC

循环打印若干次(如 5 次)。


🛠 方法一:synchronized + wait/notifyAll

思路解析

使用一个共享变量 state 表示当前轮到哪个线程。每个线程进入临界区后判断是否是自己该打印的时机,否则调用 wait() 挂起,等待唤醒。

示例代码

/*1.设置共享变量state控制线程的执行顺序2.在打印方法中传入两个参数:打印的内容, 当前线程的state3.每个线程在调用打印方法时都要传入自己对应的顺序,A:0,B:1,C:2
*/
public class PrintABC {private static int state = 0;// 设置共享变量控制线程执行顺序private static final int COUNT = 5;// 控制执行顺序private static Object lock = new Object();// 用于加锁的对象public static void main(String[] args) {Thread t1 = new Thread(() -> {try {printChar("A", 0);} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t2 = new Thread(() -> {try {printChar("B", 1);} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t3 = new Thread(() -> {try {printChar("C", 2);} catch (InterruptedException e) {throw new RuntimeException(e);}});t1.start();t2.start();t3.start();}private static void printChar(String name, int curState) throws InterruptedException {int i = 0;while(i < COUNT) {synchronized (lock) {if(state % 3 == curState) {// 是当前线程的执行顺序System.out.print(name + " ");i++;// 控制当前线程的执行的次数state++;// 轮转到下一个线程lock.notifyAll();}else {// 轮不到当前线程  wait等待lock.wait();}}}}
}

优缺点

  • ✅ 简单易懂,容易上手;
  • 使用全局的共享变量state来控制线程的执行顺序
  • ❌ 效率较低,notifyAll() 会唤醒所有线程。

🛠 方法二:ReentrantLock + Condition

思路解析

相比 synchronizedReentrantLock 提供更灵活的线程调度机制,Condition 可以精准唤醒目标线程,避免不必要的唤醒。

示例代码

    /**第四种方法:ReentrantLock + Condition 来实现更加精确的线程间通信* ReentrantLock实现加锁,解锁; Condition实现线程间的通信*/public static final int COUNT = 5;public static int state = 0;public static ReentrantLock lock = new ReentrantLock();public static Condition conA = lock.newCondition();public static Condition conB = lock.newCondition();public static Condition conC = lock.newCondition();public static void main(String[] args) {new Thread(() ->printChar("A", 0, conA, conB)).start();new Thread(() ->printChar("B", 1, conB, conC)).start();new Thread(() ->printChar("C", 2, conC, conA)).start();}private static void printChar(String name, int curState, Condition curCondition, Condition nextCondition) {for(int i = 0; i < COUNT; i++) {lock.lock();try {while(state % 3 != curState)curCondition.await();// 是当前线程  执行System.out.print(name);state++;nextCondition.signal();} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();}}}

优缺点

  • ✅ 支持精准唤醒,性能优于 notifyAll
  • ❌ 编写稍复杂,需要手动释放锁。

🛠 方法三:Semaphore 信号量控制

思路解析

使用 3 个信号量 semAsemBsemC 控制线程谁可以打印,线程执行后释放下一个信号量即可。

示例代码

    /** 第二种方法:使用Semaphore 信号量的方式控制执行顺序* 如何保证先打印A:semA, semB, semC  将A的许可设置为1,B,C的许可设置为0,则一定先执行A* 如何保证打印顺序:在打印方法中传入三个参数:name, curSem, nextSem  A-B  B-C  C-A* 执行完当前线程打印内容之后,让下一个线程release一个许可*/private static final Semaphore semA = new Semaphore(1);private static final Semaphore semB = new Semaphore(0);private static final Semaphore semC = new Semaphore(0);private static final int COUNT = 5;public static void main(String[] args) {new Thread(() -> printChar("A", semA, semB)).start();new Thread(() -> printChar("B", semB, semC)).start();new Thread(() -> printChar("C", semC, semA)).start();}private static void printChar(String name, Semaphore cur, Semaphore next) {for(int i = 0; i < COUNT;) {try {cur.acquire();System.out.print(name + " ");++i;next.release();} catch (InterruptedException e) {throw new RuntimeException(e);}}}

优缺点

  • ✅ 信号机制清晰,逻辑明确;
  • ❌ 不支持灵活的线程增删;

🛠 方法四:BlockingQueue 队列传令

思路解析

为每个线程分配一个阻塞队列,当队列有“令牌”时线程执行,执行完毕后将令牌交给下一个队列。
阻塞队列是一个线程安全的队列

  1. 队列为空时,take会阻塞
  2. 队列为满时,put会阻塞

示例代码

    /** 第三种方法:使用BlockingQueue作为令牌的方式来控制打印顺序* 创建三个队列,每个队列分别打印对应需要打印的内容* 使用令牌来控制打印的顺序,和使用semaphore类似* 在打印的方法中传入三个参数:要打印的内容,当前队列,下一个队列*/public static BlockingQueue<String> qA = new ArrayBlockingQueue<>(1);public static BlockingQueue<String> qB = new ArrayBlockingQueue<>(1);public static BlockingQueue<String> qC = new ArrayBlockingQueue<>(1);public static final int COUNT = 5;public static void main(String[] args) throws InterruptedException {new Thread(() -> printChar("A", qA, qB)).start();new Thread(() -> printChar("B", qB, qC)).start();new Thread(() -> printChar("C", qC, qA)).start();qA.put("go");}private static void printChar(String name, BlockingQueue<String> curQueue, BlockingQueue<String> nextQueue) {for(int i = 0; i < COUNT; i++) {try {curQueue.take();// 等待令牌传递System.out.print(name + " ");nextQueue.put("go");// 传递令牌} catch (InterruptedException e) {throw new RuntimeException(e);}}}

优缺点

  • ✅ 队列阻塞机制天然适合线程通信;
  • ❌ 每个线程都需独立队列,稍显繁琐。

使用SemaphoreBlockingQueue的方式其实很像;对于阻塞队列来说,是通过传递令牌的方式来交接接力棒


📌 总结对比

方法控制方式唤醒机制难度推荐场景
synchronized状态 + 模 3 判断notifyAll简单测试、学习入门
ReentrantLock状态 + Conditionsignal⭐⭐更精确唤醒,推荐实际开发使用
Semaphore信号量控制顺序release/acquire⭐⭐控制有限资源访问/固定顺序
BlockingQueue令牌传递take/put⭐⭐结构直观,适合理解通信流程

🔚 写在最后

线程按顺序轮流执行是实际开发中很常见的需求,比如:生产者消费者模型、有序打印日志、顺序处理任务等。

掌握以上几种方法不仅能应对面试题,更能提升对 Java 并发编程的理解。

如果你觉得这篇文章对你有帮助,不妨点个赞、收藏或转发给需要的朋友吧!


http://www.yayakq.cn/news/714926/

相关文章:

  • 做家电网站好it培训机构推荐
  • 温州做网站哪家好外贸seo外贸推广外贸网站建设外贸网站建设
  • 公司网站建设策划方案哈尔滨网站设计定制
  • 购物网站建设优势wordpress 技术文档
  • 微网站开发平台免费建站哪家好社区
  • 交网站建设域名计入什么科目想做棋牌网站怎么做
  • O2O网站开发工程师wang域名建的网站
  • 网站开发的数据库技术怎么联系百度推广
  • 做外贸网站 用国外空间 还是 国内空间 区别胶州市网站建设
  • 广东创粤建设有限公司网站图片转短链接生成器
  • 国外有名的设计网站Apple 手机网站制作
  • 长泰网站建设网站建设运营策划方案
  • 做医疗健康类网站需要资质吗门户网登录入口
  • 软文范文200字seo网站关键词排名优化
  • 电子商务的网站案例石家庄网络公司查封
  • 网站建设案例讯息怎样换网站logo
  • wordpress圆角阴影seo系统是什么意思
  • 那个网站做港货比较好有哪些做电子商务的网站
  • 服装企业网站模版wordpress 短网址插件
  • 网站有没有做等级测评怎么查看百度网站适配代码
  • 平陆县做网站怎样提高网站的打开速度
  • 潍坊哪家做网站做的最好网站建设需要摊销吗
  • 石家庄住房城乡建设厅网站深圳坪山比亚迪
  • 网站建设与运营总结在互联网公司上班都做啥的
  • 自己做电影网站有没有钱赚wordpress 二级链接
  • 网站建设源码修改网站备案幕布多少钱
  • 影响网站显示度的原因优秀网站制作定制
  • 工程承包去哪个网站ps和vscode做网站
  • 网站没有域名网络公司怎样推广网站
  • 网站建设专业的室内设计联盟官网论坛