小伙伴们大家好,不知道你们有没有在Java开发中遇到redis队列高并发,这个问题让你很头疼,今天小编就来讲解一下在Java中遇到redis队列高并发了,到底该怎么办。

高并发的业务场景:

我们做商品抢购功能,要面临的第一个问题就是数据不能异常,而保证数据不异常我们的解决办法有很多比如说数据库的锁机制,或者先改后查的方式都能解决,但是第二个问题来了如果我们用上述技术解决,数据是不会异常了,但是我们的服务器压力就会很大了,从而使服务器宕机,那么我们如何使服务器压力减小还能保证数据不异常呢,我们可以使用队列的思想,下面我们介绍的是使用redis队列解决高并发的问题

设计思路

用户在下订单之前当然是先查询到这个商品,在这个查询的时候,将数据库中商品的剩余数量存到redis中;

服务器在一瞬间接到成千上万的下订单请求,在控制层没有直接处理请求数据,而是先根据redis中商品的剩余数量来判断,如果>0,就将请求放到请求队列中,否则直接响应客户端“卖完了”;

考虑到数据的一致性,队列的容量就是商品的剩余数量,队列采用的是线程安全的队列LinkedBlockingQueue(单台服务器),然后通过新的线程异步处理这些请求,多台服务器的话,可以考虑使用消息队列MQ,单独用一台服务器去处理消息队列中的请求;

客户端发送订单请求之后,会收到响应,要么是剩余数量不足(卖完了),要么是请求已经被放到队列中,为下一步的轮询订单做准备;

如果响应状态是卖完了,直接提示客户,如果请求已经放入队列中,就可以根据用户id和商品id去轮询订单了;

实现步骤

说明:用java语言,springmvc框架+redis实现

准备工作,查询商品信息,将剩余数量同步到redis中 Jedis jedis = jedisPool.getResource();

BuyGood good=buyGoodService.getById(good_id);

jedis.set("residue"+good_id, good.getResidue()+"");

jedisPool.returnResource(jedis);

下订单的方法,下面直接展示代码,包括请求对象,控制层方法,请求处理线程类的具体实现

请求封装对象 public class BuyRequest {

private int good_id;//商品id

private int user_id;//用户ID

private int order_id;//订单id

private BuyOrders buyOrders;//订单信息

private int response_status;//0:未处理;1:正常;2:异常

public BuyOrders getBuyOrders() {

return buyOrders;

}

public void setBuyOrders(BuyOrders buyOrders) {

this.buyOrders = buyOrders;

}

public int getGood_id() {

return good_id;

}

public void setGood_id(int good_id) {

this.good_id = good_id;

}

public int getOrder_id() {

return order_id;

}

public void setOrder_id(int order_id) {

this.order_id = order_id;

}

public int getResponse_status() {

return response_status;

}

public void setResponse_status(int response_status) {

this.response_status = response_status;

}

public int getUser_id() {

return user_id;

}

public void setUser_id(int user_id) {

this.user_id = user_id;

}

}

处理请求的controller @Controller

@RequestMapping("/buy")

public class BuyController {

private static BuyQueuebuyqueue =null;//线程安全的请求队列

@RequestMapping("/addOrders.do")

@ResponseBody

public Object addOrders(BuyRequest buyrequest){

Mapresults = new HashMap<>();

Jedis jedis = jedisPool.getResource();

try {

//下订单之前,先获取商品的剩余数量

int residue =

Integer.valueOf(jedis.get("residue"+buyrequest.getGood_id()));

if(residue<1){//如果剩余数量不足,直接响应客户端“卖完了”

results.put("msg", "卖完了");

results.put("done", false);

BaseLog.info("addOrders results="+JSON.toJSONString(results));

return results;

}

//如果还有剩余商品,就准备将请求放到请求队列中

if(buyqueue==null){//第一次初始化请求队列,队列的容量为当前的商品剩余数量

buyqueue=new BuyQueue(residue);

}

if(buyqueue.remainingCapacity()>0){//当队列的可用容量大于0时,将请求放到请求队列中

buyqueue.put(buyrequest);

}else{//当请求队列已满,本次请求不能处理,直接响应客户端提示请求队列已满

results.put("msg", "抢购队列已满,请稍候重试!");

results.put("done", false);

return results;

}

if(!DealQueueThread.excute){//如果线程类的当前执行标志为未执行,即空闲状态,通过线程池启动线程

DealQueueThread dealQueue = new DealQueueThread(buyqueue);

ThreadPoolUtil.pool.execute(dealQueue);

BaseLog.info("Thread.activeCount()="+Thread.activeCount());

}

//请求放入到队列中,即完成下单请求

results.put("done", true);

results.put("msg", "下订单成功");

} catch (Exception e) {

results.put("done", false);

results.put("msg", "下单失败");

BaseLog.info("addOrders results="+JSON.toJSONString(results));

BaseLog.error("addOrders",e);

}finally{

jedisPool.returnResource(jedis);

}

return results;

}

}

处理请求的线程类 @Component

public class DealQueueThread implements Runnable {

private static DealQueueThread dealQueueThread;

@Autowired

BuyGoodService buyGoodService;

@Autowired

BuyOrdersService buyOrdersService;

@Autowired

JedisPool jedisPool;

private Jedis jedis;

private BuyQueuebuyqueue;

public static boolean excute = false;//线程的默认执行标志为未执行,即空闲状态

public DealQueueThread() {

}

public DealQueueThread(BuyQueuebuyqueue) {

this.buyqueue = buyqueue;

jedis = dealQueueThread.jedisPool.getResource();

}

@PostConstruct

public void init() {

dealQueueThread = this;

dealQueueThread.buyGoodService = this.buyGoodService;

dealQueueThread.buyOrdersService = this.buyOrdersService;

dealQueueThread.jedisPool = this.jedisPool;

}

@Override

public void run() {

try {

excute = true;//修改线程的默认执行标志为执行状态

//开始处理请求队列中的请求,按照队列的FIFO的规则,先处理先放入到队列中的请求

while (buyqueue != null && buyqueue.size() > 0) {

BuyRequest buyreq = buyqueue.take();//取出队列中的请求

dealWithQueue(buyreq);//处理请求

}

} catch (InterruptedException e) {

BaseLog.error("DealQueueThread:", e);

} finally {

excute = false;

}

}

public synchronized void dealWithQueue(BuyRequest buyreq) {

try {

//为了尽量确保数据的一致性,处理之前先从redis中获取当前抢购商品的剩余数量

int residue = Integer.valueOf(jedis.get("residue" +

buyreq.getGood_id()));

if (residue < 1) {//如果没有剩余商品,就直接返回

buyreq.setResponse_status(3);

return;

}

//如果有剩余商品,先在redis中将剩余数量减一,再开始下订单

jedis.decr("residue" + buyreq.getGood_id());

//将数据库中将剩余数量减一,这一步处理可以在队列处理完成之后一次性更新剩余数量

dealQueueThread.buyGoodService.minusResidue(buyreq.getGood_id());

//处理请求,下订单

BuyOrders bo = new BuyOrders();

bo.setGood_id(buyreq.getGood_id());

bo.setUser_id(buyreq.getUser_id());

int order_id = dealQueueThread.buyOrdersService.insert(bo);

BuyOrders orders = dealQueueThread.buyOrdersService.getById(order_id);

buyreq.setOrder_id(order_id);//订单id

buyreq.setBuyOrders(orders);//订单信息

buyreq.setResponse_status(1);//处理完成状态

} catch (Exception e) {

buyreq.setResponse_status(2);//异常状态

BaseLog.error("DealQueueThread dealWithQueue:", e);

}

}

}

轮询订单

思路:查询订单和剩余数量,有以下三种情况:

1)查到订单,直接跳转到确认订单并支付的页面完成支付;

2)还没有查询到订单,但是剩余数量大于0,说明请求还在队列中,继续轮询;

3)没有查到订单,剩余数量等于或小于0,说明抢购失败了,直接响应客户抢购失败;

以上就是Java中使用redis队列解决高并发的一些内容,更多相关内容请持续关注本站。

java redis队列_redis队列实现高并发怎么用?Java如何使用redis队列解决高并发?相关推荐

  1. 高并发限流:8个步骤快速解决高并发问题!

    现在很多公司的招聘信息,都会有这这么一条要求:有分布式.高并发.高负载.高可用系统设计.开发和调优经验者优先. 写这个岗位描述的HR,恨不得把自己知道的所有看上去高大上的词全都堆砌上,恨不得让别人一看 ...

  2. Java解决高并发秒杀商品

    在看本文章之前,需要了解Spring boot搭建和使用 ,本篇文章核心问题是如何解决高并发问题. 开发环境:redis缓存4.0.1,Rabbitmq消息队列,Erlang(这个跟MQ环境有关,先安 ...

  3. 三个方法解决php并发问题

    福利:[网络安全重磅福利:入门&进阶全套282G学习资源包免费分享 !] 解决php并发问题的方法有很多,具体可以使用MySQL的行级锁.乐观锁和Redis的分布式锁等技术来解决.此外,还可以 ...

  4. java消费轮询redis队列_redis实现队列

    转:https://www.cnblogs.com/nullcc/p/5924244.html 问题:如果一个并发很大的消息应用,想要根据请求的优先级来处理? 答案:用Redis 详解: 一是并发量大 ...

  5. redis java 队列_Redis 队列 Java调用简单实现

    简述 在本博客中,我们将会创建一个reids的消息队列,Redis可以被当成消息队列使用.消息会被存放在一个key-value集合中. redis消息生产者使用RPUSH命令将消息添加到队列的尾部,而 ...

  6. redis 队列_Redis系列5实现简单消息队列

    任务异步化 打开浏览器,输入地址,按下回车,打开了页面.于是一个HTTP请求(request)就由客户端发送到服务器,服务器处理请求,返回响应(response)内容. 我们每天都在浏览网页,发送大大 ...

  7. redis 队列_Redis与Rabbitmq消息队列的区别

    将redis发布订阅模式用做消息队列和rabbitmq的区别: 可靠性  redis :没有相应的机制保证消息的可靠消费,如果发布者发布一条消息,而没有对应的订阅者的话,这条消息将丢失,不会存在内存中 ...

  8. java 实现队列读写锁_史上最全的Java并发系列之Java中的锁的使用和实现介绍(二)...

    前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 种一棵树最好的时间是十年前,其次是现在 絮叨 上节是锁的第一 ...

  9. 死磕Java并发:J.U.C之阻塞队列:ArrayBlockingQueue

    作者:chenssy 来源:Java技术驿站 ArrayBlockingQueue,一个由数组实现的有界阻塞队列.该队列采用FIFO的原则对元素进行排序添加的. ArrayBlockingQueue为 ...

最新文章

  1. rsync+sersync实现数据文件实时同步
  2. 调用别的类中的变量(但是还是有问题)
  3. 《More Effective C++》读书笔记
  4. php函数有哪三种,【后端开发】php函数可以分为哪三种
  5. Spring 3.1 Environment Profiles--转载
  6. php俩个字符串合并,php分割合并两个字符串的函数实例
  7. SSM+Druid实现动态多数据源切换(已实践)
  8. 【深度学习】重大里程碑!VOLO屠榜CV任务,无需额外数据,首个超越87%的模型...
  9. 关于Spring事务tx:annotation-driven/的理解(Controller可以使用@Transactional)
  10. linux系统如何拨号上网连接,教你在Linux下如何使用ADSL拨号上网
  11. Redis-3.2.4服务搭建
  12. 解决outlook无法启动
  13. 微服务SpringCloud系列
  14. 片段中的findViewById
  15. 数据仓库和数据库有什么区别
  16. Mac 安装JDK 8
  17. Spider爬虫笔记[更新中...]
  18. 唐灵州吕氏夫人墓志的史证和书证价值
  19. 河南省普通高中学业水平测试计算机,河南省普通高中信息技术学业水平测试综合测试题3(有答案)...
  20. 神奇宝贝/数码宝贝分类器笔记-机器学习-李宏毅2021

热门文章

  1. 吧友们, 昨天的「百度贴吧」还差一个用户界面, 代码都在这儿了...
  2. 【Android 控件使用及源码解析】 GridView规则显示图片仿微信朋友圈发图片
  3. python函数def里面嵌套def_Python的函数嵌套的使用方法
  4. oracle实例注册监听,Oracle 19C 监听无法动态注册实例
  5. GIAC专访丨DolphinDB研发总监周信静:实时计算,连接时序数据库和核心业务
  6. java tlv生成,TLV格式数据JAVA编解码
  7. 一个图片压缩 免费 api接口
  8. python实现tailf或者filebeat功能
  9. 云台和华为p30pro_p30pro和mate30pro对比
  10. Excel快速选中某一列的所有数