经典问题 | 线程打印ABA问题

问题描述

有三个线程,分别命名为 ThreadA、ThreadB 和 ThreadC。请设计一个程序,使得它们循环打印输出字符串 "A"、"B"、"C",打印顺序为 "ABCABCABC..."。要求使用线程同步机制确保按照指定顺序打印。

解决思路

线程的元素判断问题

线程A, B,C三个线程, 当存在竞争的时候, 第一个元素应该打印A, 这个时候打印B的线程进来了, 为了要保证打印ABC是顺序执行的,因此不能让打印B的线程打印.

那线程是打印的什么元素以及和我现在要打印的元素是否匹配是不是就构成了一个条件? 

使用一个共享的计数器, 默认从0开始, 每打印一个元素, 次数+1, 严格按照0,1,2顺序打印ABC

条件1 :  因此计数器的次数对3取模, 就知道当前应该打印什么元素.

条件2 :  在条件1的基础上, 判断线程携带的元素是否是需要打印的元素即可.

这里有个小技巧:

在ASCII码表中,每个字符都有一个对应的整数值。对于大写字母 'A' ,'B','C', 其ASCII码分别为 65 , 66,  67.

因此线程携带的字母减去'A'构成了条件, 与计数器对3取模的数值进行比较, 就知道当前线程是否可以打印字母.

并发问题

在多线程环境中,多个线程并发执行可能导致不确定性的结果。在这个问题中,我们有三个线程,每个线程负责打印一个字符。线程执行快慢问题也会导致顺序紊乱.

为了确保每一次只有一个线程可以执行, 需要有上锁逻辑.

完整的思路: 使用线程等待-通知机制结合共享计数器来实现线程同步。

使用一个共享的计数器 counter,初始值为0,表示当前应该由哪个线程打印。

  1. 三个线程分别为 ThreadA、ThreadB 和 ThreadC,它们负责打印字符 "A"、"B" 和 "C"。
  2. 每个线程在打印自己对应的字符之前,首先检查 counter 的值,只有当 counter 的值模3等于当前线程应该打印的字符的序号时,才进行打印。
  3. 打印完成后,递增 counter 的值,并使用 notifyAll 通知所有线程。
  4. 其他线程在被唤醒后重新检查 counter 的值,如果不满足条件,继续等待。

java代码示例

public class PrintABAThreeThreads {private static final int TOTAL_COUNT = 10; // 打印总次数private static final Object lock = new Object(); // 用于同步的锁private static int counter = 0; // 共享计数器private static void print(String message) {for (int i = 0; i < TOTAL_COUNT; i++) {synchronized (lock) {while (counter % 3 != message.charAt(0) - 'A') {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print(message);counter++;lock.notifyAll();}}}public static void main(String[] args) {Thread threadA = new Thread(() -> print("A"));Thread threadB = new Thread(() -> print("B"));Thread threadC = new Thread(() -> print("C"));threadA.start();threadB.start();threadC.start();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/608005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

尤雨溪:框架挖坑靠文档来补,这算 PUA 用户吗?丨 RTE 开发者日报 Vol.122

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

JWT令牌(Token)设计

JWT&#xff08;JSON Web Token&#xff09;是一种基于开放标准的令牌&#xff08;Token&#xff09;&#xff0c;用于在不同实体之间传递和验证信息。它由三部分组成&#xff1a;头部&#xff08;Header&#xff09;、载荷&#xff08;Payload&#xff09;和签名&#xff08;S…

Centos Unable to verify the graphical display setup

ERROR: Unable to verify the graphical display setup. 在Linux下安装Oracle时 运行 ./runInstaller 报错 ERROR: Unable to verify the graphical display setup. This application requires X display. Make sure that xdpyinfo exist under PATH variable. No X11 DISPL…

使用Python脚本自动发送个性化微信消息通知

需求&#xff1a; 需要向单位同事定期&#xff08;每周一次&#xff09;发送每个人的业务情况提醒&#xff0c;同时也要发送新的登录token。如果采用邮件大家也不常看&#xff0c;提醒效果很差&#xff0c;同时邮件传输非常不安全&#xff0c;单位很多人邮箱默认密码不改&…

使用开源通义千问模型(Qwen)搭建自己的大模型服务

目标 1、使用开源的大模型服务搭建属于自己的模型服务&#xff1b; 2、调优自己的大模型&#xff1b; 选型 采用通义千问模型&#xff0c;https://github.com/QwenLM/Qwen 步骤 1、下载模型文件 开源模型库&#xff1a;https://www.modelscope.cn/models mkdir -p /data/…

微信小程序中组件内生命周期如何调用组件内方法

在组件的.js文件中使用 Component({/*** 组件的属性列表*/properties: {},/*** 组件的初始数据*/data: {},/*** 组件的方法*/methods:{async getData() {},},/*** 组件的生命周期*/lifetimes:{// 在组件实例进入页面节点树时执行attached:function(){this.getData() //调用}} …

JavaScript-数组-笔记

1.定义数组 数组&#xff1a; 可以存储任意数据类型&#xff0c;元素之间使用英文逗号隔开 1&#xff09;使用new关键字定义数组 var 变量名 new Array() &#xff1b;定义空数组 var 变量名 new Array(数据1&#xff0c;数据2) &#xff1b; 定义有元素的数组 注意&#xff…

Jmeter 性能 —— 吞吐量与并发用户数关系!

1、吞吐量和并发用户数的关系 2、已知在线用户数为3000&#xff0c;算出对应的并发用户数 ①我们常用的确定并发用户数的公式是&#xff1a; C活动用户数操作时间/系统运行时间 如每天最大在线用户数为3000人&#xff0c;每个用户平均操作时间为1小时&#xff0c;系统运行时…

【后退N帧协议】- 协议应用与局限分析

后退N帧协议是计算机网络通信中常用的一种流量控制协议&#xff0c;用于确保数据的可靠传输。本文将深入探讨后退N帧协议的原理、应用场景及局限性。 后退N帧协议的核心思想是在发送端发送数据时&#xff0c;等待接收端返回的确认信号。发送端每次发送N帧数据&#xff0c;并等…

零基础学Python网络爬虫案例实战 全流程详解 高级进阶篇

零基础学Python网络爬虫案例实战 全流程详解 入门与提高篇 零基础学Python网络爬虫案例实战 全流程详解 高级进阶篇 编辑推荐 本书讲解了Python爬虫技术的高级进阶知识&#xff0c;帮助有一定爬虫基础的读者进一步提高爬虫技术。本书详解了突破反爬机制的常用手段以及Scrapy和…

基于SSM+Vue的学校社团管理系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

工业相机——靶面尺寸、像元尺寸、分辨率 、传感器尺寸

文章目录 1 靶面尺寸、像元尺寸、分辨率2 相机传感器的感光区尺寸规格1 靶面尺寸、像元尺寸、分辨率 工业相机基本知识理解:靶面尺寸、像元尺寸、分辨率 1、靶面尺寸:由Sensor对角线长度表示,单位英寸,这里的1英寸=16mm 2、像元尺寸:单个感光元件的大小,一般都是正方形…

C# OpenCvSharp DNN FreeYOLO 人脸检测人脸图像质量评估

目录 效果 模型信息 yolo_free_huge_widerface_192x320.onnx face-quality-assessment.onnx 项目 代码 frmMain.cs FreeYoloFace FaceQualityAssessment.cs 下载 C# OpenCvSharp DNN FreeYOLO 人脸检测&人脸图像质量评估 效果 模型信息 yolo_free_huge_widerfa…

Qt隐式共享浅析

一、什么是隐式共享 Qt 的隐式共享&#xff08;implicit sharing&#xff09;机制是一种设计模式&#xff0c;用于在进行数据拷贝时提高效率和减少内存占用。 在 Qt 中&#xff0c;许多类&#xff08;如 QString、QList 等&#xff09;都使用了隐式共享机制。这意味着当这些类…

色标在matplotlib和plottable中

是这样的&#xff0c;我有一个数组[-4.4, -2.8, -2.6, -2.2, -1.1, 1.1, 1.2, 1.3, 3.6, 6.0, 6.4, 12.3]&#xff0c;它需要绘制散点图&#xff0c;点的颜色来代表数值大小&#xff1b;同时&#xff0c;也需要在plottable上作为一列显示&#xff0c;同样用颜色来代表数值的大小…

HarmonyOS应用开发学习笔记 ArkTS 布局概述

一、布局概述 布局指用特定的组件或者属性来管理用户页面所放置UI组件的大小和位置。在实际的开发过程中&#xff0c;需要遵守以下流程保证整体的布局效果 确定页面的布局结构。分析页面中的元素构成。选用适合的布局容器组件或属性控制页面中各个元素的位置和大小约束。 二…

【JUC】进程和线程

目录 &#x1f4e2;什么是进程?&#x1f3a1;什么是线程?&#x1f680;进程和线程的区别?&#x1f3a2;Java 线程和操作系统的线程有啥区别&#xff1f;&#x1f396;️JDK21的虚拟线程&#x1f3af;虚拟线程和平台线程的对比 &#x1f4e2;什么是进程? 进程是程序的一次执…

Zabbix“专家坐诊”第223期问答汇总

来源&#xff1a;乐维社区 问题一 Q&#xff1a;Zabbix 5.0安装完mysql之后怎么备份&#xff1f;忘记mysql当时创建的密码了&#xff0c;怎么样能查看设置的密码&#xff1f; A&#xff1a;mysql初始化密码在 /var/log/mysqld.log中可以看到&#xff0c;搜关键字temporary pas…

Android studio TabHost应用设计

一、xml布局文件: 添加TabHost控件 <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.…

【算法分析与设计】移动零

题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0…