java长轮询

在服务端向页面主动推送消息的业务场景下,有长轮训和websocket两种思路。

springboot 和websocket使用:https://blog.csdn.net/u014203449/article/details/102902078

现在看看长轮询:

 

设想一个业务场景:A用户打开页面,要求实时刷新数据,B用户操作新增数据,A页面刷新。

1.页面

长轮询的做法是,A用户打开页面,就请求一个接口,js ajax请求时设置一个超时时间,比如60s。

 $.ajax({
  url:'',  //请求的URL
  timeout : 60000, //超时时间设置,单位毫秒
  type : 'get',  //请求方式,get或post
  data :{},  //请求所传参数,json格式
  dataType:'json',//返回的数据格式
  success:function(data){ //请求成功的回调函数
    alert("成功");
  },

2.接口

而接口中,判断数据是否有变化,如果有变化直接将数据返回,如果没有变化,将线程挂起60s,60s内有变化就返回数据,无变化返回空。

线程挂起可以用sleep 或者LockSupport.park 方法将其堵塞。

3.打断阻塞

但堵塞后如何能发现数据变化,从而返回数据呢?因为是另一个用户B线程进行操作导致的数据变化。

1.轮询。可以在接口中循环sleep 几秒,去查询数据是否发生变化。

2.B用户线程操作后,可以找到A用户的长轮询线程,然后进行打断。A用户线程写个判断打断逻辑,如果打断标志为ture,就查询数据返回。

B线程如何找到A线程呢?可以设置一个全局线程安全集合,比如CopyOnWriteArraySet,把线程放进去。

4.下一次轮询

而js 在接口响应后,继续发起一次请求,监听下一次数据的变化。

5.长轮询案列

正好看到了Apollo配置中心,配置中心服务端如何通知客户端配置发生了变化,这就用到了长轮询。

Apollp的地址:https://github.com/ctripcorp/apollo/wiki/Apollo%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E8%AE%BE%E8%AE%A1#21-%E9%85%8D%E7%BD%AE%E5%8F%91%E5%B8%83%E5%90%8E%E7%9A%84%E5%AE%9E%E6%97%B6%E6%8E%A8%E9%80%81%E8%AE%BE%E8%AE%A1

里面写到了:

  1. 客户端会发起一个Http请求到Config Service的notifications/v2接口,也就是NotificationControllerV2,参见RemoteConfigLongPollService
  2. NotificationControllerV2不会立即返回结果,而是通过Spring DeferredResult把请求挂起
  3. 如果在60秒内没有该客户端关心的配置发布,那么会返回Http状态码304给客户端
  4. 如果有该客户端关心的配置发布,NotificationControllerV2会调用DeferredResult的setResult方法,传入有配置变化的namespace信息,同时该请求会立即返回。客户端从返回的结果中获取到配置变化的namespace后,会立即请求Config Service获取该namespace的最新配置。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,轮询可以通过异步Servlet、WebSocket或者基于线程的实现来实现。 具体实现步骤如下: 1. 在Servlet中,需要使用异步Servlet来实现轮询,即在Servlet中使用 `request.startAsync()` 方法来启动异步处理。 2. 在异步处理中,需要使用 `AsyncContext` 对象来设置超时时间、处理完成后的回调函数等。在异步处理中,可以使用 `response.getWriter()` 方法来获取输出流,并向客户端输出数据。 3. 在客户端中,需要使用 JavaScript 来发起轮询请求。可以使用 `XMLHttpRequest` 或者 `fetch` 方法来发起请求,并在请求返回时处理响应数据。 以下是一个简单的基于 Servlet 的轮询实现示例: ```java @WebServlet("/long-polling") public class LongPollingServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { AsyncContext asyncContext = request.startAsync(); asyncContext.setTimeout(30000); // 设置超时时间为30秒 asyncContext.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent event) throws IOException { System.out.println("Long polling completed"); } @Override public void onTimeout(AsyncEvent event) throws IOException { System.out.println("Long polling timeout"); event.getAsyncContext().getResponse().getWriter().write("timeout"); // 返回超时信息 event.getAsyncContext().complete(); // 结束异步处理 } @Override public void onError(AsyncEvent event) throws IOException { System.out.println("Long polling error"); event.getAsyncContext().getResponse().getWriter().write("error"); // 返回错误信息 event.getAsyncContext().complete(); // 结束异步处理 } @Override public void onStartAsync(AsyncEvent event) throws IOException { System.out.println("Long polling started"); } }); // 在异步处理中等待事件的发生 new Thread(() -> { try { // 模拟事件的发生 Thread.sleep(10000); response.getWriter().write("event happened"); // 返回事件信息 asyncContext.complete(); // 结束异步处理 } catch (Exception e) { e.printStackTrace(); } }).start(); } } ``` 客户端可以使用以下 JavaScript 代码来发起轮询请求: ```javascript function longPolling() { fetch('/long-polling') .then(response => response.text()) .then(data => { if (data === 'timeout') { console.log('Long polling timeout'); longPolling(); } else if (data === 'error') { console.log('Long polling error'); longPolling(); } else { console.log('Event happened:', data); longPolling(); } }) .catch(error => { console.error('Long polling error:', error); longPolling(); }); } longPolling(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值