秒杀
需求
- 10个礼物20个客户抢
- 随机10个客户获取礼物,另外10无法获取礼物
任务类
记得给共享资源加锁
public class MyTask implements Runnable{// 礼物列表private ArrayList<String> gifts ;// 用户名private String username;public MyTask( String username, ArrayList<String> gifts) {this.username = username;this.gifts = gifts;}@Overridepublic void run() {// 模拟网络延迟try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 加锁 锁对象是gifts 保证线程安全synchronized (gifts) {// 抢礼物grabGift();}}// 抢礼物private void grabGift() {if (gifts.isEmpty()) {System.out.println("礼物已经被抢完了," + username + "没有抢到礼物");return;}// 输出礼物信息 随机抢一个System.out.println(username + "抢到了" + gifts.remove((int) (Math.random() * gifts.size()))) ;}}
测试
1、创建线程池
2、执行任务
3、关闭线程池
// 礼物列表 有10个礼物
ArrayList<String> gifts = new ArrayList<String>() {{add("iPhone 12");add("MacBook Pro");add("iPad Pro");add("Apple Watch");add("AirPods Pro");add("HomePod");add("Apple TV");add("Apple Music");add("Apple Arcade");add("Apple Fitness");
}};// 使用线程池 模拟20个用户同时抢礼物
ExecutorService executorService = Executors.newFixedThreadPool(7);
for (int i = 0; i < 20; i++) {executorService.execute(new MyTask("用户" + i, gifts));
}
// 关闭线程池
executorService.shutdown();
结果
双人取款机
ATM任务类
- 默认同一个账户id等同于同一个锁对象
- 取款的时候加锁,去完款就解锁
public class ATMTask implements Runnable{private String accountId;private double amount;private static Map<String, Double> balanceMap = new HashMap<>();private static final Map<String, Object> lockMap = new ConcurrentHashMap<>();static {balanceMap.put("1", 1000.0);balanceMap.put("2", 1000.0);}public ATMTask(String accountId, double amount) {this.accountId = accountId;this.amount = amount;}private double getBalance(String accountId) {return balanceMap.get(accountId);}private void updateBalance(String accountId, double amount) {if (getBalance(accountId) < amount) {System.out.println("账户余额不足");return;} else {System.out.println("用户" + accountId + "取款成功,取款金额:" + amount);balanceMap.put(accountId, getBalance(accountId) - amount);// 移除锁对象lockMap.remove(accountId);}}/*** 这个方法接受一个账户ID作为参数,* 然后检查lockMap中是否已经存在对应该账户ID的锁对象。* 如果不存在,它会使用putIfAbsent方法添加一个新的锁对象到lockMap中。* 这个方法最终返回账户ID对应的锁对象。* 这种方式确保了每个账户ID都有一个唯一的锁对象,而且这个过程是线程安全的。* @param accountId 账户ID* @return*/private static Object getLock(String accountId) {// 如果不存在则添加lockMap.putIfAbsent(accountId, new Object());// 如果存在则返回return lockMap.get(accountId);}@Overridepublic void run() {synchronized (getLock(this.accountId)) {updateBalance(accountId, amount);}}
}
线程池模拟
public static void main(String[] args) {// 两个线程对同一个账户取款ATMTask task1 = new ATMTask("1", 800);ATMTask task2 = new ATMTask("1", 800);ATMTask task3 = new ATMTask("2", 700);ATMTask task4 = new ATMTask("2", 300);// 创建线程池ExecutorService executor = Executors.newFixedThreadPool(2);// 提交任务executor.submit(task1);executor.submit(task2);executor.submit(task3);executor.submit(task4);// 关闭线程池executor.shutdown();}