【问题标题】:Cancelling method calls when the same method is called multiple time多次调用同一方法时取消方法调用
【发布时间】:2013-09-14 09:51:19
【问题描述】:

我想我在这里描述的东西可能有一个名字,但我不知道。所以我的第一个问题是知道这种技术的名称。

下面是一个示例:假设您正在网页上实现实时搜索。每次用户在搜索框中输入内容时,您都会触发一个新的搜索查询,并且结果会尽可能频繁地更新。 这是一件愚蠢的事情,因为您将发送比您实际需要的更多的查询。每 2-3 个字母发送一次请求或最多每 100 毫秒发送一次请求可能就足够了。

因此,一种技术是安排在键入键后立即执行查询,如果仍有计划但未执行的查询,请取消它们,因为它们现在已经过时了。


现在更具体地说,是否有特定的模式或库可以在 Java 中解决这个问题?

我必须在 Swing 应用程序中解决问题,我使用了 ExecutorService,它返回了可以取消的 ScheduledFutures。问题是我必须为我想要“缓冲”的每个方法调用手动创建一个 Runnable,并跟踪每个 Future 以取消它。

我确定我不是第一个实现这样的东西的人,所以一定有一个可重用的解决方案吗?可能在 Spring 中带有注释和代理?

【问题讨论】:

  • 我不认为你有任何模式。流程很简单:您第一次运行异步任务并设置 flag = "BUSY",这意味着:在第一次请求没有得到响应之前不要开始下一个搜索。
  • 它被称为*request throttling
  • @JarrodRoberson :谢谢,这帮助我找到了一些资源。但是节流似乎与我描述的略有不同。通过节流,您可以立即分派请求,然后在请求过多时阻止较新的请求(较早的请求具有优先级)。我描述的方法延迟了初始请求,以便在新的请求到达时可以取消它们(以后的请求具有优先权)。
  • 这只是语义;阻止,取消,延迟,等等。这个概念是你明确地管理请求/事务的速率,而不是让它成为一个消防水管。
  • @user177800 也称为去抖动

标签: java design-patterns debouncing


【解决方案1】:

鉴于其他答案,经过一番搜索,似乎确实没有库可以满足我的需求。

我创建了一个并将其放在 GitHub 上。这个问题的未来读者可能会觉得它很有趣。

https://github.com/ThomasGirard/JDebounce

我认为它还不是很好,但至少它可以工作并且可以声明式使用:

@Debounce(delayMilliseconds = 100)
public void debouncedMethod(int callID, DebounceTest callback) { }

【讨论】:

  • +1 您应该接受这个答案,它解决了问题,并且是目前唯一在线可用的 Java 解决方案(或极少数解决方案之一)。
【解决方案2】:

如果不使用一些额外的基础设施,就像使用 executor 和 futures 一样,这在 Java 中是无法解决的。在 Java 中不可能以语法简洁的方式解决这个问题。

您将始终需要某种方法结果包装器,因为该机制会立即返回,但稍后会检索实际结果。在您的情况下,这是通过 Future 完成的。

您始终需要能够以允许延迟执行的方式指定要执行的代码。在大多数语言中,这是使用函数指针或函数值或闭包来完成的。在 Java 中,缺少这些语言特性,这通常是通过传递一个对象来实现的,该对象实现了某种接口,例如 Runnable、Callable,它允许延迟执行代码块。还有其他选项,但都不是简单的,例如使用动态代理。

tl;博士

不能在 Java 中以简洁的方式做到这一点。

【讨论】:

  • Java 8 似乎对 lambda 函数有一些支持。
  • 也许,我还没有研究 Java 8,因为很多企业产品还不支持它。
【解决方案3】:

你需要的是debouncing。您应该检查jQuery Throttle/Debounce plugin(顺便说一句,它完全独立于jQuery,除了使用相同的命名空间)。 debounce part 涵盖了您所需要的内容:

使用 jQuery throttle / debounce,你可以传递一个延迟和函数到 $.debounce 获得一个新函数,当重复调用时, 每“一堆”调用只执行原始函数一次, 有效地将多个顺序调用合并为一个 在开始或结束时执行。

Underscore.js有同样的方法:

_.debounce(function, wait, [immediate]) 

创建并返回传递函数的新去抖动版本 这将推迟其执行直到wait 毫秒之后 自上次调用以来已过去。对实施有用 只有在输入停止到达后才会发生的行为。 例如:渲染一个 Markdown 评论的预览,重新计算 窗口停止调整大小后的布局,等等。

// example: debounce layout calculation on window resize
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

[编辑]

我错误地阅读了“Javascript”而不是 Java。之后实际的 Java 解决方案是 written by OP

【讨论】:

  • 谢谢。去抖动是我一直在寻找的术语。我 +1 了你的答案,除非有人可以给我更多特定于 java 的东西,否则我会接受它。
  • @ARRG:哦,废话,我以为是 Javascript(因此有这些示例)。 :)
  • 是的,谢谢。我一直在寻找的是在维护良好的库中对此的支持(如 _.js 或 jQuery,但在 java 世界中)。但我想这是在 javascript 中比在 Java 中更经常需要的东西。
  • @ARRG:我不时在 C# 中使用它,例如在控件之间切换焦点时刷新相关菜单和工具栏(例如复制/粘贴)时。虽然没有 Java 实现。
猜你喜欢
  • 2012-11-08
  • 1970-01-01
  • 2013-10-22
  • 1970-01-01
  • 2019-12-22
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多