Java Web 应用开发案例|模拟 12306 抢票

举报
TiAmoZhang 发表于 2023/07/31 14:07:00 2023/07/31
【摘要】 模拟12306网上抢票的业务场景。春节等高峰时期,车票资源非常紧张,因此在约定时间放票,会存在大量抢票行为。服务器为了缓解并发高峰时的压力,抢票请求会用消息中间件进行排队处理。出票行为在服务器的独立线程中进行,这样主线程主要用于接收购票请求,异步线程用于出票,会大大缓解服务器的压力。

Java Web应用开发案例|模拟12306抢票

模拟 12306 网上抢票的业务场景。春节等高峰时期,车票资源非常紧张,因此在约定时间放票,会存在大量抢票行为。服务器为了缓解并发高峰时的压力,抢票请求会用消息中间件进行排队处理。出票行为在服务器的独立线程中进行,这样主线程主要用于接收购票请求,异步线程用于出票,会大大缓解服务器的压力。

01、案例:12306 抢票

操作步骤如下所述。

(1) 新建控制器支持异步模式。

@WebServlet(asyncSupported = true,urlPatterns ="/AuctionSvl")
public class AuctionSvl extends HttpServlet

(2) 控制器的 service()方法是一个高并发环境。每个 HTTP 请求都使用独立的 request 对象。调用 request.startAsync(),为每个 HTTP 请求创建一个异步回应的环境。

public void service(HttpServletRequest request HttpServletResponse response)
throws ServletException,IOException 
(System.out.println("servlet 主线程:”+ Thread.currentThread().getId()) //lineNum 为行号String linenum = request.getParameter("lineNum”); AsyncContext act = request.startAsync(); act.getRequest().setAttribute("linenum”linenum); AuctionListener.add(act);

(3) 所有异步回应在独立线程中统一处理。AuctionListener 实现了 ServletContextListener 监听器,因此在 Tomcat 启动时被加载。BlockingQueue 为阻塞队列,装载所有与请求对应的 AsyncContext 对象。

 public class AuctionListener implements ServletContextListener
 ( private static final BlockingOueue < AsyncContext > 
 queue= new LinkedBlockingOueue < AsyncContext >(); 
 private volatile Thread thread;
 public static void add(AsvncContext c)queue.add(c); 
 contextInitialized(); //参见下面的代码实现

ServletContextListener 的 contextInitialized()方法代码如下,独立的后台线程从队列 queue 中顺序提取 AsyncContext 对象,然后分别调用每个 AsyncContext 的 response 对象,给不同的客户端回应数据。

 public void contextInitialized(ServletContextEvent servletContextEvent) 
 (thread = new Thread(new Runnable()
 public void run(){ while (true)
 AsyncContext acontext = null;
 while ( queue.peek() != null)
 try{ acontext = (AsyncContext)queue.poll();
 ServletResponse response = acontext.getResponse();
 response.setContentType("text/html;charset = utf - 8");
 PrintWriter out = response.getWriter();
 Thread.sleep(200);String name ="异步线程:” +Thread.currentThread().getId();
 long duration = System.currentTimeMillis(); //提取前面输入的行号,并输出 
 out.println(acontext.getRequest().getAttribute("linenum") } "+ name +”"duration) 
 out.close(); catch (Exception e)
 throw new RuntimeException(e.getMessage(),e);
 finally(if(acontext != null)acontext.complete(); 
 thread.start(); } }

(4) 客户端模拟多用户并发抢票,循环发出 20 个异步请求。

 S.ajax( url:"AuctionSvl" type: "post" dataType:"html" data: data, timeout:50000 cache:false dataFilter:function (data,type)
 (return data; success:function(data,testStatus)var dataArray = Array();
 dataArray = data.split("")* 填充表格 *$("# tablel").append("< tr id='tr"+ i+ "class = 'mytr'></tr>") ;
 for(var j=0;j< dataArray.length; j++)[ $ ("#tr"+ i).append("< td>" + dataArray[j] + "</td>") error:function(msg) );

(5) 对比服务器异步回应和同步回应,异步抢票结果见图 1。在这个示例中,所有用户的并发购票请求,都会先存在一个阻塞队列中,然后由一个后台异步线程,顺序从阻塞队列中提取请求,当出票结束后再回应客户端。这样做的好处是服务器的压力很小,虽然用户的等待时间较长,但是这样保证了用户购票请求的正确处理。

■ 图 1 12306 抢票

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。