一直想知道线程池是如何使用的,从网上查阅了大量的资料,接下来就按照我自己的理解整理一下若依线程池的使用。
线程池的使用场景
高并发场景,例如秒杀商品,当秒杀商品使用的是单线程,那么所耗费的时间可想而知。小编在这里想了几个技术栈来解决秒杀商品,包括使用线程池(比单线程时间要快很多,不用频繁的创建线程,关闭线程,因为池子里面有创建好的线程,直接使用就可以)、redis分布式锁、rabbitmq异步处理具体业务。具体例子(你的商城网站,这次要有10件商品进行秒杀,假设每件商品的抢购人数是一万人,那么1秒你的接口接收到的请求就是10万次,这个就属于高并发,首先你的代码应该是接收到请求,用线程池处理这么多的请求,这里就节约了很多时间,然后根据每个商品的ID加分布式锁,确保商品没有超卖,然后就是rabbitmq去异步处理扣减库存和生成订单等等)小编这里只举例一个最常见的场景,剩余的场景还有很多。
若依线程池的配置
相信很多小伙伴看到上面线程池的使用场景,也对线程池的重要性有了深刻的了解,那么下面来看一下若依的线程池的配置
若依是在项目启动的时候,就把线程池注入到spring容器中,主要涉及到两个线程池的使用,如图:
用到最多的就是第一张图,里面代码的意思其实就是配置线程的核心数量、最大数量、空闲时间、拒绝策略,这里不过多介绍,下面直接教大家如何使用。
若依线程池的使用
//获得线程池
private ThreadPoolTaskExecutor executor = SpringUtils.getBean("threadPoolTaskExecutor");
//把业务放到线程池里面执行
executor.submit(processSeckill(String productId, String userId) );
//主要业务
@Async("seckillTaskExecutor")
public void processSeckill(String productId, String userId) {
String lockKey = "seckill_lock:" + productId;
String requestId = IdUtils.fastSimpleUUID();
int expireTime = 10; // 锁的过期时间(秒)
try {
if (redisLockService.acquireLock(lockKey, requestId, expireTime)) {
try {
// 开启事务管理
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// 查询商品库存
ShopProduct product = shopProductService.selectShopProduct(productId);
if (product == null || product.getStock() <= 0) {
LOG.error("商品ID={} 库存不足", productId);
return;
}
// 减少库存
product.setStock(product.getStock() - 1);
shopProductService.updateShopProduct(product);
// 记录订单(假设有一个订单服务)
// orderService.createOrder(productId, userId);
txManager.commit(status);
LOG.info("用户ID={} 成功秒杀商品ID={}", userId, productId);
} catch (Exception e) {
txManager.rollback(status);
LOG.error("秒杀失败: 商品ID={}, 用户ID={}", productId, userId, e);
}
} finally {
redisLockService.releaseLock(lockKey, requestId);
}
} else {
LOG.error("获取锁失败,秒杀请求失败: 商品ID={}, 用户ID={}", productId, userId);
}
} catch (Exception e) {
LOG.error("处理秒杀请求异常: 商品ID={}, 用户ID={}", productId, userId, e);
}
}
结尾
对于线程池来说,作者也只是小白,底层代码在这里我也没有列出来,想了解底层代码的可以再去看一眼其他大神的笔记,同时以上所有内容仅供参考,有什么问题尽管提出来。