【问题标题】:use of invokeLaterinvokeLater 的使用
【发布时间】:2010-12-09 07:07:38
【问题描述】:

很确定所有这些方法都行得通,但我希望能就哪种方法最好提出意见。

考虑一下(不幸的)场景,您有 UI 更改代码和合理密集(平均 500 毫秒)的逻辑代码混合且不可分割。所有不断变化的 ui 组件都在一个面板上。

01 new Thread(){
02  public void run(){
03 
04  for (int i = 0; i < 100; i++){
05      // some processing
06      doSomething();
07      // update some ui components
08      panel.doSomeUi();
09  }
10 
11  panel.revalidate();
12  panel.repaint();
13 
14 }}.start();

您会选择以下 3 种方法中的哪一种?为什么?

  1. 将所有代码封装在invokeLater中
  2. 在 doSomeUi() 中调用 invokeLater,然后再次调用以进行重新验证/重新绘制
  3. 仅在最后使用 invokeLater 进行重新验证/重新绘制

对于我来说:

选项 1 会在所有处理发生时挂起事件处理线程 (EPT)

选项 2 在创建许多新的可运行文件时会考虑开销,并且在特殊情况下,如果组件需要一些后续的 ui 更改才能生效,则可能会导致 ui 更新为半完成状态

选项 3 将是最有效的,但可能存在一些线程安全问题

热衷于听取其他意见。

【问题讨论】:

    标签: java swing


    【解决方案1】:

    doSomeUi () some 应该包含在 invokeLater () 并且 应该触发任何必要的重绘/重绘——Swing UI 线程将在您继续计算时进行绘制。

    在现代 VM 上创建大量短期 Runnable 的开销很小,应该不是问题。

    所以,选项 2(建议修改)应该是它。在编写多线程代码时,缓慢而正确总是比快速且随机出现错误要好。

    【讨论】:

      【解决方案2】:

      首先我会让它运行单线程。作为其中不可分割的一部分,我会确保我有良好的代码(例如,不扩展 ThreadJPanel),将“业务”逻辑和 UI、测试等很好地分离。这可能不会令人印象深刻,但它是可交付的。检查到版本控制。然后也许看看有没有我可以并行做的小而热的部分。

      有一些极端的方法可以解决多线程问题。在没有共享状态的情况下,我们可以将不可变的操作事件从 UI 中排入队列,并将不可变的更新事件排入队列以替换模型的 UI 副本。或者,我们可以共享状态并非常小心锁定(我建议可能工作的最大锁 - 小心回调)。

      请注意,您不必为每件小事都添加侦听器,这可能会很有用。您可以使用粗粒度侦听器,然后快速扫描数据结构以获取更新。

      需要注意的重要一点是,UI 发送到“业务”模型的操作和反向的状态更新应尽可能解耦(即从SwingWorker 运行)。

      【讨论】:

      • 首先,我什么时候提到过扩展 JPanel?其次,虽然您的建议听起来不错,但我不明白它与问题的关系。我已经明确表示,为了争论,好的分离是不可能的。也许这是有缺陷的问题,但我想要解决的更多问题是在整个过程中锁定 EDT、在过程中多次锁定 EDT 或在 EDT 之外执行大部分 UI 任务和然后通过最后在 EDT 上重新绘制/验证来“重新同步”。
      • panel.doSomeUi(); 建议JPanel 扩展给我。也许doSomeUi 是一些JPanel 方法的替代品,但EDT 之外的选择有限。如果分离是“不可能的”,正如我在第一段中建议的那样,那么首要任务就是做“不可能的”。
      • 好的,我应该写 doSomeUi(panel);它本来是一个半 sudo 代码,例如,它会在单个容器的范围内建议 ui 代码。
      【解决方案3】:

      重新验证和重新绘制是线程安全的。它们内置了自己的 invokeLater 东西,您可以随时从任何线程调用 revalidate 和 repaint。它甚至非常聪明,如果您在实际验证任何内容之前调用 revalidate 一千次,它会将所有这千次调用合并为一个调用。

      【讨论】:

        【解决方案4】:

        您是否阅读了Java Lesson: Concurrency in Swing 并考虑使用工作线程。还要检查TumbleItem Example

        教训明确地说:

        事件调度线程上的任务 必须快速完成;如果他们不这样做, 未处理的事件备份和用户 界面变得无响应。

        当一个 Swing 程序需要执行时 一个长时间运行的任务,它通常使用 工作线程之一

        【讨论】:

        • 谢谢,但这并没有太大变化,基本上你是说你会使用一个实用程序类或一个实用程序类的许多实例来做同样的事情......我没用过SwingWorker 因为比较新,但我的理解是它只是一个方便的类,封装了一个两部分的任务——处理+ui。对吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-13
        • 2013-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-24
        相关资源
        最近更新 更多