天天看點

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元
           

繼續閱讀