自学内容网 自学内容网

线程池案例

秒杀

需求

  • 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;
    }

    @Override
    public 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);
    }

    @Override
    public 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();
    }

结果

在这里插入图片描述


原文地址:https://blog.csdn.net/qq_40603125/article/details/140305412

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!