一、前言
再来系统动手学习一下Java并发编程。
知识点:CountDownLatch
的发令枪使用模式;红包均分,最后一个分不完的解决方法
抢红包的需求,每个红包均分,最后一个除外
1. 设置红包总额
2. 设置红包的个数
3. 模拟抢红包的人数 (细节:涉及余额分配 10元3个人抢,得把钱分完)
4. 抢红包,同一时间多个人可以同时开始 (细节:要保证同时开始)
二、代码案例
package com.lvzb.concurrent;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 抢红包案例
*
* @author: lvzb31988
* @date: 2023/01/09 20:00
*/
@Slf4j
public class GrabRedEnvelopeTest {
public static void main(String[] args) throws InterruptedException {
int totalAmount;
int num;
int peopleNum;
CountDownLatch countDownLatch = new CountDownLatch(1);
Scanner scanner = new Scanner(System.in);
System.out.println("请输入红包金额:");
totalAmount = scanner.nextInt();
System.out.println("请输入拆分多少个红包:");
num = scanner.nextInt();
System.out.println("请输入多少个人抢:");
peopleNum = scanner.nextInt();
RedEnvelope redEnvelope = new RedEnvelope(totalAmount, num, countDownLatch);
// for (int i = 1; i <= peopleNum; i++) {
// new Thread(redEnvelope, "第" + i + "个人").start();
// }
// countDownLatch.countDown();
ExecutorService pool = Executors.newFixedThreadPool(peopleNum);
for (int i = 1; i <= peopleNum; i++) {
pool.execute(redEnvelope);
}
countDownLatch.countDown();
// 不关闭池的话,程序不会结束
pool.shutdown();
}
/**
* 抢红包的需求,每个红包均分,最后一个除外
* 1. 设置红包总额
* 2. 设置红包的个数
* 3. 模拟抢红包的人数 (细节:涉及余额分配 10元3个人抢,得把钱分完)
* 4. 抢红包,同一时间多个人可以同时开始 (细节:要保证同时开始)
*/
public static class RedEnvelope implements Runnable {
/**
* 红包总额
*/
private int totalAmount;
/**
* 红包个数
*/
private int num;
/**
* 每个红包均分的 额度
*/
private int eachAmount;
/**
* 特殊处理最后一个红包的额度,防止分不完
*/
private int lastAmount;
// countDownLatch 的发令枪模式
private CountDownLatch countDownLatch;
// 保证线程安全
private Object lock = new Object();
public RedEnvelope(int totalAmount, int num, CountDownLatch countDownLatch) {
this.totalAmount = totalAmount;
this.num = num;
this.countDownLatch = countDownLatch;
this.eachAmount = totalAmount / num;
// 最后一个红包金额 = 总额 - (红包总数-1)* 每个红包的数
this.lastAmount = totalAmount - (num - 1) * eachAmount;
}
@Override
public void run() {
synchronized (lock) {
try {
countDownLatch.await();
} catch (InterruptedException e) {
// 如果当前线程异常,就可以通知线程应该中断了
Thread.currentThread().interrupt();
e.printStackTrace();
}
int currentAmount;
if (num != 1) {
currentAmount = eachAmount;
} else {
currentAmount = lastAmount;
}
if (num > 0) {
num--;
System.out.println(Thread.currentThread().getName() + ": hhhh 我抢到了" + currentAmount + "元...");
} else {
System.out.println(Thread.currentThread().getName() + ": 没有抢到,错过一个亿...");
}
}
}
}
}
输出结果参考
参考资料
- Java 最新版并发编程入门与春晚抢红包实战
- CountDownLatch的使用场景