笔者在前两天参加面试的时候被问到了一个场景问题,觉得自己之前准备的确实不妥当,在此抛砖引玉分享思路。
背景了解
首先明确问题,100个人的群组里让你去发一个红包,可以被88个人抢。那么1. 你怎么解决他们争抢的问题。2. 你怎么决绝红包金额分配问题,同时要让红包分配的金额有趣。
竞态条件
在程序开发中,竞态条件指的是多个线程同时访问共享资源时,由于没有采用合适的同步机制,导致结果的正确性无法保证。在社交平台项目开发中,竞态条件可能会出现在以下场景中:
- 用户登录状态:当多个用户同时访问同一个用户的个人主页时,可能会出现竞态条件。例如,当一个用户登录时,其他用户可能会同时访问该用户的个人主页,如果没有采用合适的同步机制,可能会出现用户信息不一致的问题。
- 用户消息列表:当多个用户同时刷新自己的消息列表时,可能会出现竞态条件。例如,当一个用户刷新自己的消息列表时,其他用户也可能会同时刷新该用户的消息列表,如果没有采用合适的同步机制,可能会出现消息列表不一致的问题。
- 文件读写:当多个线程同时读写同一个文件时,可能会出现竞态条件。例如,当多个用户同时编辑同一个文档时,如果没有采用合适的同步机制,可能会出现文档内容不一致的问题。
在以上场景中,我们可以采用线程安全的同步机制,例如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】-腾讯云开发者社区-腾讯云