- 抢红包是在并发场景下操纵和获取资源,只需要将操作和获取的过程建立线程安全机制即可;
- 抢红包需要多线程同时访问同一共享资源,所以将共享资源作为成员变量注入线程类中供其调用 (使用操纵内存的方式);
实现过程
红包类:
// 红包实体,共享变量,通过直接操作内存实现
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元