概述
- 在公司题库看到了这个,有点好奇微信的红包算法是怎么实现的,知乎看到了这个答案:微信红包的随机算法是怎样实现的? - 陈鹏的回答 - 知乎
- 总结下核心的几点:
- 内存实时计算模型,这个和电商体系下很多离线计算的红包不同,故在点击红包页面和领取红包详情页其实是两个状态,从用户动线角度手慢则无其实也合理
- 判定是否还有红包可领取时类似商品库存一样有个分布式锁的判定,当领取红包后CAS模式写库,然后再跟财付通对账
- 算法本身也并不是绝对均等,做到了大致均等
实现
PS:这里我们假设红包是有上下界的,即每个人拿到的红包有最大和最小值限制,那么当每次计算时需要check仍未分配的红包可能的最大值和最小值,详见代码:
public class WxRandomHongbao {
//总人数和总红包数
private static final double TOTAL_AMOUNT = 1000.0;
private static final int TOTAL_USERS = 6;
private static double getRandomVal(double min, double max) {
Random random = new Random();
return random.nextDouble() * (max - min) + min;
}
/**
* 红包分配算法
*
* @param remainUser 剩余人数
* @param remainMoney 剩余红包
* @param minMoney 最小值
* @param maxMoney 最大值
* @return
*/
public static double getRandomMoney(int remainUser, double remainMoney,
double minMoney, double maxMoney) {
if (remainUser == 1) {
return (double)Math.round(remainMoney * 100) / 100;
}
//计算随机红包上下界限制
double minBound = Math.max(remainMoney - (remainUser - 1) * maxMoney, minMoney);
double maxBound = Math.min(remainMoney - (remainUser - 1) * minMoney, maxMoney);
double money = getRandomVal(minBound, maxBound);
//微信的随机算法
//double value = remainMoney / remainUser * 2;
//money = Math.max(minMoney, money);
//money = Math.min(maxMoney, money);
money = Math.floor(money * 100) / 100;
return money;
}
public static void main(String[] args) {
double minMoney = 100.0;
double maxMoney = 200.0;
double totalAns = 0.0;
double[] amounts = new double[TOTAL_USERS];
int remainUsers = TOTAL_USERS;
Double remainMoney = TOTAL_AMOUNT;
for (int i = 0; i < TOTAL_USERS; i++) {
amounts[i] = getRandomMoney(remainUsers, remainMoney, minMoney, maxMoney);
remainUsers--;
remainMoney -= amounts[i];
}
for (Double amount : amounts) {
totalAns += amount;
}
System.out.println(Arrays.toString(amounts));
System.out.println(String.format("%.2f", totalAns));
}
}