【问题标题】:making efficient implementation of this Java MouseListener Logic高效实现此 Java MouseListener Logic
【发布时间】:2012-01-24 01:45:31
【问题描述】:

我有一个 MouseListener 线程,每次点击时都会调用这个方法:

public void mousePressed(MouseEvent event){

    //my Logic here

}

现在发生的情况是,在很短的时间内就有如此多的点击,而我这里的逻辑需要更多时间来处理。我所期望的是,进一步的点击将被丢弃,并且此方法将在最新的即将点击中继续。

但是发生了什么,当逻辑正在处理时,传入的 clics 排队,即使点击停止,qued 点击继续调用这个 mousePressed 方法,结果我有多个延迟执行。

不幸的是,我无法控制侦听器(为什么它会查询并继续发送延迟的点击),所以在这种情况下,你能告诉我什么是有效的处理方式,这样我就不会因为我的处理延迟。

我认为最明显的方法是使用另一个线程,但我想知道这可能会在短时间内触发这么多线程,或者有什么方法可以锁定一个线程,而其余的点击只是通过空循环?

【问题讨论】:

  • 您可能想要模拟 Swing 如何处理重绘请求——当它们堆积起来时它会忽略请求。请在此处查看更多信息:Painting in AWT and Swing。是的,我认为无论如何,您都希望使用后台线程,可能是线程池。
  • @HovercraftFullOfEels,这是 JNI 方法,其中实际的鼠标侦听器来自本机代码,不涉及 Swing。
  • 好的,所以如果我只是启动一个新线程然后调用该方法,至少我不会错过任何点击,尽管结果仍然延迟并且在许多并行线程中,我想使用一些 volatile布尔标志可能是答案,我想是的。
  • 这是否是 Swing 无关紧要,因为原理是相同的。
  • 请注意,问题的第一行是错误的,MouseListener 不是 Thread。它只是给 Swing 并由 Swing 执行的某种回调对象(碰巧在主线程之外的另一个线程上执行它,但这不会使 MouseListener 本身成为一个线程)。

标签: java multithreading swing concurrency event-listener


【解决方案1】:

更新:请参阅 Phillip 的 cmets,了解为什么这不适用于 Swing!

很遗憾您无法访问eventListener。理想的解决方案是在执行回调时取消注册回调。

这是一个解决方案,它模拟在执行回调函数时取消注册,假设您希望队列中的点击消失:

private AtomicBoolean engaged = new AtomicBoolean(); // thread-safe boolean

public void mousePressed(MouseEvent event){
    if (!engaged.get()) {
        engaged.set(true);

        // your logic here

        engaged.set(false);
    }
}

AtomicBoolean 充当测试和设置锁,防止多个线程同时运行按下事件回调。锁定期间排队的按下将被消散。

【讨论】:

  • 我已经测试过了,但它似乎对输出没有影响,可能是我遗漏了什么,但我会在早上再试一次,现在是凌晨 3:30,谢谢
  • 这个没有效果,因为Swing不是多线程的。所有事件都在同一个线程中顺序执行,所以当mousePressed方法被调用时,之前的调用总是已经结束。
  • 通常将engaged.set(false) 调用放入finally 块中是非常重要的。否则任何异常或提前返回都会永久禁用该组件。
  • 查看我的答案以获得(未经测试的)解决方案。
【解决方案2】:

一种解决方案是访问用户单击的组件并在处理MouseListener 期间禁用它。这样它就不会接受新的点击。这将有额外的好处,给用户视觉反馈,他不应该在这个时候点击组件。

您可以通过MouseEvent访问该组件:

public void mousePressed(MouseEvent event) {
  event.getComponent().setEnabled(false);
  try {

    // ....

  } finally {
    event.getComponent().setEnabled(true);
}

一般来说,虽然您不应该在 Swing 事件侦听器线程中进行过多的计算,因为 Swing 还需要它来处理其他事件和绘制。您应该使用单独的线程来完成实际工作,并在 MouseListener 中启动它们。您还可以使用 ExecutorService 来简化此操作。 在整个计算过程中禁用 gui 组件以向用户提供反馈仍然是一个好主意。

编辑: 这个解决方案当然依赖于 Swing。任何类似的解决方案都取决于您的 GUI 库的详细信息,因此如果您使用自己的 GUI 库,那么您就是自己的一个。

您当然可以使用涉及单独线程的通用解决方案来完成工作。我真的在这里推荐ExecutorService,如果您不需要关心细节,只需提交任务即可执行。然后,您可以有一个简单的 volatile 布尔变量,它指示当前是否正在执行操作,是否应忽略新的点击。

【讨论】:

  • 谢谢,实际上我无法访问该组件,因为它可能是 chrome、windows 媒体播放器等,我只是连接到系统 dll 以获得点击。在我的实现中,一切都是基于 CLI 的,此时没有涉及任何 Swing GUI,基本上在我的逻辑中,我使用 JNA 获取活动窗口标题,将其与以前的值进行比较,然后忽略它是否相同(对于同一组件上的多次点击),否则如果活动组件不同,则调用另一个方法。
  • 等一下,您根本没有使用 Swing?您需要在问题中说明这一点。它有标签“swing”并提到了著名的 Swing 类的名称,所以我假设 Swing 是调用您的代码的那个。如果您不使用 Swing,则可能不应该使用 Swing 类,因为这可能会让您的代码的未来读者感到非常困惑。
  • 所以现在我已经用一个简单的 if(boolean){new Thread().start()} 实现了它,在线程中我将布尔值设置为 false,完成后将其设置回真的
猜你喜欢
  • 1970-01-01
  • 2010-11-19
  • 2015-06-19
  • 2013-03-28
  • 1970-01-01
  • 2011-06-24
  • 2012-10-15
  • 2022-09-29
  • 1970-01-01
相关资源
最近更新 更多