java轮训算法_如何在Java中实现响应式轮询

假设您需要从外部源流式传输数据,但该数据源本身不支持push,因此您不得不求助于定期轮询。如何在Java中实现这一点,尽可能简单,同时保持响应?

大概的概念

在我们深入研究代码之前,让我们首先讨论需求和总体思路。我们需要做的是基本上以固定速率触发获取操作,阻止客户端直到新数据可用。此外,让我们假设我们希望保持响应,因此我们不应无限期地阻止,但是在给定的最大时间量过去之后取消阻塞,之后客户端可以做出相应的反应(再试一次,中止或做其他事情)。

为了满足这些要求,我们将实现Token Bucket算法的变体,它通常用于流量整形。在该算法中,固定数量的令牌周期性地放置在指定容量的虚拟桶中。同时,另一个等待执行某些操作的线程(例如通过网络发送数据包)检查存储桶的内容,如果存在足够的令牌,则将其从存储桶中删除,然后执行操作。在本文中,我们将通过模拟容量为1且仅使用一个使用者线程的存储桶来简化算法。

履行

由于我们的存储桶容量为1,因此它只有两种状态(满和空)。这可以用单个布尔值表示,true表示full和false表示空:

private boolean fetch = true ; //我们马上开始取

此外,我们需要安排一个以固定费率定期“填补空白”的任务。这是使用ScheduledExecutorService完成的:

void start() {ScheduledExecutorService es = Executors.newScheduledThreadPool(1);es.scheduleAtFixedRate(this::scheduleFetch, FETCH_INTERVAL, FETCH_INTERVAL, TimeUnit.MILLISECONDS);}什么是scheduleFetch操作是什么样子?它只是将fetch变量设置为true(填充存储桶)并通知另一个(提取)线程,此时可能正在等待我们的存储桶状态发生变化。有关为什么必须同步下两个方法的讨论,请参阅此堆栈溢出问题。

synchronized void scheduleFetch () {fetch = true ;notify ();}接下来,我们将提供一个操作,如果存储桶已满或在给定的最大时间内阻塞,等待它变满,返回存储桶的最新状态,并最终清空它:

由于我们不会阻止比WAIT_LIMIT更长的时间,因此保证此方法的返回时间不会超过WAIT_LIMIT。我们需要这种保证来确保响应能力,我们很快就会看到。总的来说,操作向调用者发出信号,是否允许执行获取,返回的时间不超过WAIT_LIMIT毫秒。

有了这个,并假设实际的获取操作(通过网络发送请求,解释响应等)是在doFetch方法中实现的,我们最终可以实现阻塞轮询方法:

List poll() throws InterruptedException {return awaitFetch() ? doFetch() : null;}在这里,null向客户端发出信号,表明还没有新的数据可用。实际上,这是Kafka Connect中需要实现的确切协议源连接器,并且所描述的实现在PLC4X 源连接器中使用。

备注

该程序有两个主要参数:WAIT_LIMIT和FETCH_INTERVAL。前者控制客户端的响应性 - WAIT_LIMIT越低,在没有新数据可用的情况下,控制返回客户端的速度越快。

第二个参数控制最大请求(采样)速率。它实际上是一个上限,因为有效采样率可能更低 - 也就是说,当获取操作比FETCH_INTERVAL执行的时间更长时。

备选方案

尽管提出的解决方案有效,但仍有其他选择。一种这样的替代方案是直接获取调度的周期性任务中的数据,而不是通知获取(客户端)线程。但是,由于我们需要阻止客户端线程等待新数据,因此我们必须将从周期性任务获取的结果传递回客户端,例如通过阻塞队列。

另一种方法是使用现成的实用工具类这类任务,例如RateLimiter从谷歌番石榴库。这将进一步简化实施。但是,您必须向项目添加另一个库依赖项,这取决于具体情况,可能适合您。

结论

通过使用Token Bucket算法的变体,使用Java平台的两个低级同步原语:等待和通知,可以非常容易地实现简单的响应式轮询。虽然常识要求你永远不要搞乱基本同步原语并在java.util.concurrent中使用抽象,但这个例子表明,如果它完成了工作,有时可以破坏规则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值