- 搶紅包是在并發場景下操縱和擷取資源,隻需要将操作和擷取的過程建立線程安全機制即可;
- 搶紅包需要多線程同時通路同一共享資源,是以将共享資源作為成員變量注入線程類中供其調用 (使用操縱記憶體的方式);
實作過程
紅包類:
// 紅包實體,共享變量,通過直接操作記憶體實作
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元