多线程无锁红包实现方案
背景
朋友面试遇到过写好红包的场景,遂自己尝试了下。刚开始在如何分配的时候还是有点疑惑,后来慢慢解决,并写了一个无锁的版本,希望大家一起讨论下。
如果大家用得到,帮忙点个赞哈。
代码
@Data
public class RedPacket {
//红包总额
private Double total;
//红包份数
private Integer counts;
//红包分隔之后的载体
private List<Double> values;
//用来获取下标
private AtomicInteger taskCounts;
//红包公平概率
private Double fairRate;
private DecimalFormat decimalFormat =new DecimalFormat("#.00");
public RedPacket(Double total, Integer counts,Double fairRate) {
this.total = total;
this.counts = counts;
taskCounts = new AtomicInteger(counts);
dealFairRate(fairRate);
caculate(total,counts,this.fairRate);
}
private void dealFairRate(Double fairRate) {
fairRate = fairRate<0?0:fairRate;
fairRate = fairRate>1?1:fairRate;
this.fairRate = fairRate;
}
public String get(){
final int flag = taskCounts.getAndDecrement();
if(flag>=0){
return decimalFormat.format(values.get(flag));
}else {
return "手速慢了,该红包已经被抢空了";
}
}
private void caculate(Double total, Integer counts,Double fairRate) {
values = doubleMeanMethod(total,counts,fairRate);
}
public static double nextDouble(final double min,final double max){
return min+((max-min)*new Random().nextDouble());
}
public static String format(double value){
return new java.text.DecimalFormat("0.00").format(value);
}
public static List<Double> doubleMeanMethod(double money, int number,double fairRate){
final ArrayList<Double> doubles = new ArrayList<>();
if (money<=0&&number<1) {
return null;
}
//一般频率均分,其余的随机。可以自己调整平分概率
double avg = money*fairRate;
money = money - avg;
double avgP = avg/number;
double amount,sum = 0;
int remainNumber = number;
//int i =1;
while (remainNumber-->1){
if(fairRate!=1.0){
amount = nextDouble(0.01,money/remainNumber);
//sum+=amount+avgP;
//System.out.println("第" + i++ + "个人的领取的红包金额为:" + format(amount+avgP));
money-=amount;
doubles.add(amount+avgP);
}else {
doubles.add(avgP);
}
}
doubles.add(money+avgP);
//System.out.println("第" + i++ + "个人的领取的红包金额为:" + format(money+avgP));
//sum+=money+avgP;
//System.out.println("验证红包总金额为:" + format(sum));
return doubles;
}
public static void main(String[] args) throws InterruptedException {
final RedPacket redPacket = new RedPacket(100.00, 10,0.0);
for (int i = 0; i <20 ; i++) {
CompletableFuture.runAsync(()->{
final String s = redPacket.get();
System.out.println(s);
});
}
Thread.sleep(10000);
System.out.println("完成");
}
}