多线程无锁红包实现方案

多线程无锁红包实现方案

背景

朋友面试遇到过写好红包的场景,遂自己尝试了下。刚开始在如何分配的时候还是有点疑惑,后来慢慢解决,并写了一个无锁的版本,希望大家一起讨论下。

如果大家用得到,帮忙点个赞哈。

代码

@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("完成");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值