竞态条件?如何设计一个抢红包的程序? 说说你的思路

news/2025/2/22 4:48:08/

笔者在前两天参加面试的时候被问到了一个场景问题,觉得自己之前准备的确实不妥当,在此抛砖引玉分享思路。


背景了解

首先明确问题,100个人的群组里让你去发一个红包,可以被88个人抢。那么1. 你怎么解决他们争抢的问题。2. 你怎么决绝红包金额分配问题,同时要让红包分配的金额有趣。

竞态条件

在程序开发中,竞态条件指的是多个线程同时访问共享资源时,由于没有采用合适的同步机制,导致结果的正确性无法保证。在社交平台项目开发中,竞态条件可能会出现在以下场景中:

  1. 用户登录状态:当多个用户同时访问同一个用户的个人主页时,可能会出现竞态条件。例如,当一个用户登录时,其他用户可能会同时访问该用户的个人主页,如果没有采用合适的同步机制,可能会出现用户信息不一致的问题。
  2. 用户消息列表:当多个用户同时刷新自己的消息列表时,可能会出现竞态条件。例如,当一个用户刷新自己的消息列表时,其他用户也可能会同时刷新该用户的消息列表,如果没有采用合适的同步机制,可能会出现消息列表不一致的问题。
  3. 文件读写:当多个线程同时读写同一个文件时,可能会出现竞态条件。例如,当多个用户同时编辑同一个文档时,如果没有采用合适的同步机制,可能会出现文档内容不一致的问题。

在以上场景中,我们可以采用线程安全的同步机制,例如synchronized关键字、ReentrantLock类、CountDownLatch类、Semaphore类等,来避免竞态条件的产生。同时,我们还可以采用合适的并发策略,例如线程池、信号量等,来提高系统的并发性和性能。

解决思路

处理争抢问题

当时脑海中最初出现的就是用Redis实现分布式锁的方式来处理争抢问题。

比如可以生成一段参考代码,这里的红包金额分配仅仅采用平均值,不够有趣。但是能保证争抢问题得到改善。

看参考资料的描述

问:并发性处理:红包如何计算被抢完?

答:cache会抵抗无效请求,将无效的请求过滤掉,实际进入到后台的量不大。cache记录红包个数,原子操作进行个数递减,到 0 表示被抢光。财付通按照 20万笔每秒入账准备,但实际还不到 8万每秒

public class GrabRedPackService {private static final String REDPACK_KEY = "grab_red_pack";private static final String USER_LOCK_KEY = "user_lock";public static int grabRedPackService(String redpackId, String userId) {// 尝试获取分布式锁String lockValue = UUID.randomUUID().toString();int result = jedisClient.setNX(USER_LOCK_KEY, lockValue);if (result == 1) {// 获取成功,执行红包分配逻辑Map<String, Object> redPackMap = jedisClient.hgetall(REDPACK_KEY + ":" + redpackId);BigDecimal totalAmount = (BigDecimal) redPackMap.get("total_amount");int totalUsers = (Integer) redPackMap.get("total_users");BigDecimal userAmount = new BigDecimal(totalAmount.doubleValue() / totalUsers);String[] users = (String[]) redPackMap.get("users");Arrays.sort(users);int i = users.length - 1;for (String user : users) {if (user.equals(userId)) {// 抢到红包,将分配结果存储回Redis中jedisClient.hset(REDPACK_KEY + ":" + redpackId, "user_" + i, userAmount.toString());return 1;}i--;}// 没有抢到红包,释放分布式锁jedisClient.del(USER_LOCK_KEY);return 0;} else {// 获取失败,返回“fail”或者其他特殊返回值return 0;}}
}

如果有需求,也可以改代码为while(true)+超时的乐观锁机制不断重试。 

处理红包金额有趣的问题

1、抢红包的过程 2、随机法 3、均值法。具体可参考下方的参考资料。


参考资料

互斥锁,同步锁,临界区,互斥量,信号量,自旋锁之间联系是什么? - 胖君的回答 - 知乎 https://www.zhihu.com/question/39850927/answer/242109380

最全解密微信红包随机算法(含代码实现)-腾讯云开发者社区-腾讯云

【大厂面试题】如何设计一个抢红包算法?_哔哩哔哩_bilibili

Redis乐观锁解决高并发抢红包的问题【redis】-腾讯云开发者社区-腾讯云


http://www.ppmy.cn/news/1051377.html

相关文章

CTFhub-sql注入-绕过空格过滤

常用绕过空格过滤的方法&#xff1a; /**/、()、%0a 1.判断是否存在sqli注入 1 1/**/union/**/select/**/11 1/**/union/**/select/**/12 如果1/**/union/**/select/**/11的显示结果与1/**/union/**/select/**/12的显示结果不一样&#xff0c; 与1的结果一样说明存在注入…

PostMan 测试项目是否支持跨域

使用PostMan可以方便快速的进行跨域测试。 只需要在请求头中手动添加一个Origin的标头&#xff0c;声明需要跨域跨到的域&#xff08;IP&#xff1a;端口&#xff09;就行&#xff0c;其余参数PostMan会自动生成。添加此标头后&#xff0c;请求会被做为一条跨域的请求来进行处…

问道管理:沪指失守3100点 机构判断“市场底”渐行渐近

8月21日&#xff0c;沪深两市股指盘中全线走低&#xff0c;三大股指收盘均跌超1%&#xff0c;其间沪指收盘指数今年以来初次失守3100点&#xff0c;创业板指更是3年多来初次跌破2100点。截至收盘&#xff0c;沪指跌1.24%报3092.98点&#xff0c;深证成指跌1.32%报10320.39点&am…

音视频 ffplay命令-主要选项

选项说明-x width强制显示宽带-y height强制显示高度-video_size size帧尺寸 设置显示帧存储(WxH格式)&#xff0c;仅适用于类似原始YUV等没有包含帧大小(WxH)的视频-pixel_format format格式设置像素格式-fs以全屏模式启动-an禁用音频&#xff08;不播放声音&#xff09;-vn禁…

MySQL 存储函数

文章目录 1.简介2.创建存储函数3.调用存储函数4.查看存储函数5.修改存储函数6.删除存储函数参考文献 1.简介 MySQL 存储函数&#xff08;Stored Function&#xff09;和存储过程类似&#xff0c;也是存储在数据库中的程序&#xff0c;但是它会返回一个计算结果。 存储函数可以…

前端面试:【Redux】状态管理的精髓

嘿&#xff0c;亲爱的Redux探险家&#xff01;在前端开发的旅程中&#xff0c;有一个强大的状态管理工具&#xff0c;那就是Redux。Redux是一个状态容器&#xff0c;它以一种可预测的方式管理应用的状态&#xff0c;通过Store、Action、Reducer、中间件和异步处理等核心概念&am…

在发送邮件时遇到的错误

Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) // 配置邮件信息Properties props new Properties(); // props.put("mail.smtp.host", "smtp.163.com");props.…

流媒体服务器SRS的搭建及QT下RTMP推流客户端的编写

一、前言 目前市面上有很多开源的流媒体服务器解决方案&#xff0c;常见的有SRS、EasyDarwin、ZLMediaKit和Monibuca。这几种的对比如下&#xff1a; &#xff08;本图来源&#xff1a;https://www.ngui.cc/zz/1781086.html?actiononClick&#xff09; 二、SRS的介绍 SRS&am…