笔者在前两天参加面试的时候被问到了一个场景问题,觉得自己之前准备的确实不妥当,在此抛砖引玉分享思路。
背景了解
首先明确问题,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
最全解密微信红包随机算法(含代码实现)-腾讯云开发者社区-腾讯云