秒殺
需求
- 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();}