天天看点

Java多线程实现简单抢红包

  • 抢红包是在并发场景下操纵和获取资源,只需要将操作和获取的过程建立线程安全机制即可;
  • 抢红包需要多线程同时访问同一共享资源,所以将共享资源作为成员变量注入线程类中供其调用 (使用操纵内存的方式);

实现过程

红包类:

// 红包实体,共享变量,通过直接操作内存实现
public class RedPack{
   
    // 红包剩余数量
    int remain;
    // 总金额
    double total;
	
    public RedPack (int remain, double total) {
        this.remain = remain;
        // 保留两位小数
        this.total = new BigDecimal(total).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

	// 抢红包的动作,加上了synchronized进行并发控制
    synchronized public double grab() {
        // 抢到的结果返回给线程展示
        double result;
        // 场景 1:还剩最后一个红包,直接拿走
        if (remain == 1) {
            result = new BigDecimal(total).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            total = 0;
            remain--;
        // 场景 2:超过一个红包,生成一个(0, total)之间的随机金额
        } else if (remain > 1) {
            result = new BigDecimal((Math.random()*total)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            total -= result;
            remain--;
        // 场景 3:红包被抢完了
        } else {
            result = 0;
        }
        return result;
    }
}
           

线程:用户类

public class User implements Runnable{

	// 用户编号,区分线程
    int num;
    // 引入共享变量
    RedPack rp;
    // 抢到的金额
    double money;

    public User (int num, RedPack rp) {
        this.num = num;
        this.rp = rp;
    }

    @Override
    public void run() {
        System.out.println("用户" + num + "尝试抢红包");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 抢红包
        money = rp.grab();
        if (money > 0) {
            System.out.println("用户" + num + "抢到" + money + "元");
        } else {
            System.out.println("用户" + num + "未能抢到红包");
        }
    }
}
           

主类:

public class Main {
	// 抢红包用户数
    static final int user = 5;
    // 红包个数
    static final int remain = 4;
    // 总金额
    static final double total = 10;

    public static void main(String[] args) {
        RedPack rp = new RedPack(remain, total);
        System.out.println("抢红包开始,当前红包剩余" + total + "元");
        // 启动用户数量的线程
        for (int k = 1; k <= user; k++) {
            new Thread(new User(k, rp)).start();
        }
    }
}
           

运行结果:

抢红包开始,当前红包剩余10.0元
	用户1尝试抢红包
	用户3尝试抢红包
	用户2尝试抢红包
	用户5尝试抢红包
	用户4尝试抢红包
	用户3未能抢到红包
	用户1抢到0.52元
	用户4抢到6.99元
	用户2抢到0.5元
	用户5抢到1.99元
           

继续阅读