java - Swing Java 中的累积可运行项

标签 java swing runnable swingworker swingx

作为学习 SwingWorker 的一部分,我在浏览源代码时注意到了一个名为 AccumulativeRunnable 的东西。从 AccumulativeRunnable 类定义的注释中,我明白何时使用它,但是当我检查示例代码时,我想到了几个问题。

下面是 AccumulativeRunnable 抽象类中的注释和示例代码。

An abstract class (AccumulativeRunnable) to be used in the cases where we need to perform some actions on an appendable set of data.
The set of data might be appended after the is sent for the execution. Usually such Runnables are sent to the EDT.

Usage example: Say we want to implement JLabel.setText(String text) which sends string to the JLabel.setTextImpl(String text) on the EDT. In the event JLabel.setText is called rapidly many times off the EDT we will get many updates on the EDT but only the last one is important. (Every next updates overrides the previous one.) We might want to implement this in a way that only the last update is delivered.

  AccumulativeRunnable<String> doSetTextImpl =
  new  AccumulativeRunnable<String>()} {

      protected void run(List<String> args)} {
          //set to the last string being passed
          setTextImpl(args.get(args.size() - 1));
      }
  }

  void setText(String text) {
      //add text and send for the execution if needed.
      doSetTextImpl.add(text);
  }

问题

  1. 抽象类 AccumulativeRunnable implements Runnable 。 这意味着 AccumulativeRunnable 类应该实现运行 方法对吗?但我只能看到protected abstract void run(List<T> args); 。这如何成为 Runnable接口(interface)。
  2. 为什么 add() AccumulativeRunnable 类的方法是 synchronized ?。有人可以用一个简单的例子来解释这一点吗? 以我上面提供的示例为例。
  3. arguments里面add()的方法 AccumulativeRunnable 类将为 null ?有人可以用一个简单的例子来解释这一点吗? 以我上面提供的示例为例。
  4. 如何 add()方法接收一个数组 (T...args) ?.有人可以吗 用一个简单的例子或我提供的例子来解释这一点 如上所述。
  5. 在上面的例子中,当我们调用doSetTextImpl.add(text);时它 调用add() AccumulativeRunnable 类的方法。但这怎么 内部调用run()方法?。我的意思是谁在调用我们 实现run()内部方法。

AccumulativeRunnable 中的整个代码:

public abstract class AccumulativeRunnable<T> implements Runnable {
    private List<T> arguments = null;

    /**
     * Equivalent to {@code Runnable.run} method with the
     * accumulated arguments to process.
     *
     * @param args accumulated argumets to process.
     */
    protected abstract void run(List<T> args);

    /**
     * {@inheritDoc}
     *
     * <p>
     * This implementation calls {@code run(List<T> args)} mehtod
     * with the list of accumulated arguments.
     */
    public final void run() {
        run(flush());
    }

    /**
     * appends arguments and sends this {@code Runnable} for the
     * execution if needed.
     * <p>
     * This implementation uses {@see #submit} to send this
     * {@code Runnable} for execution.
     * @param args the arguments to accumulate
     */
    @SafeVarargs
    @SuppressWarnings("varargs") // Copying args is safe
    public final synchronized void add(T... args) {
        boolean isSubmitted = true;
        if (arguments == null) {
            isSubmitted = false;
            arguments = new ArrayList<T>();
        }
        Collections.addAll(arguments, args);
        if (!isSubmitted) {
            submit();
        }
    }

    /**
     * Sends this {@code Runnable} for the execution
     *
     * <p>
     * This method is to be executed only from {@code add} method.
     *
     * <p>
     * This implementation uses {@code SwingWorker.invokeLater}.
     */
    protected void submit() {
        SwingUtilities.invokeLater(this);
    }

    /**
     * Returns accumulated arguments and flashes the arguments storage.
     *
     * @return accumulated arguments
     */
    private synchronized List<T> flush() {
        List<T> list = arguments;
        arguments = null;
        return list;
    }
}

最佳答案

  1. 答案是 Runnable.run() 的以下实现。从编译器的角度来看,run(List<T>)与接口(interface)声明的方法无关,它只是具有(巧合)相同名称的不同方法。

    public final void run() { run(flush()); }

  2. 在图形环境中,您有很多并发性,并且 synchronized防止同时从两个线程调用该方法,否则您将创建所谓的竞争条件,其中“更快”线程对列表的更新会丢失。在这种特定情况下,如果synchronized,则可能会发生这种竞争条件。 add(T...) 中缺失并且两个线程试图同时将第一个元素添加到列表中。

  3. 在通过 add(T) 添加第一个元素之前。 arguments是必须执行的所有操作的列表。如果您创建一个新的 AccumulativeRunnable<T>arguments属性将是 null (参见第 2 行)直到添加第一个元素。

  4. T...称为“可变参数参数”。这基本上只是语法糖,允许您调用 add通过以下任何一种方式(有关更多信息,请随时阅读 this ):

    1. add(firstObject) 。这将在内部将您提供的一个对象转换为只有一个元素 (firstObject) 的 T 类型数组。

    2. add(firstObject, secondObject, thirdObject)等等,有任意数量的参数。所有这些参数将被打包到一个数组中并提供给函数。

    3. add(objectArray)其中 objectArray 是 T 类型的实际数组。在本例中,内部变量 arguments将简单地引用提供的数组。

  5. 答案写在您提供的引文中:

    Usually such Runnables are sent to the EDT.

    EDT = 事件调度线程,一个位于 Swing 框架深处的“隐藏”线程,用于处理所有按钮单击等。可能触发 run() 的事情方法例如调用frame.paint() (或者无论如何调用该方法,我使用的是 JFX,所以我不是 Swing 方面的专家)、按钮单击、鼠标移动等。

关于java - Swing Java 中的累积可运行项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60340260/

相关文章:

java - 如何从 Java 代码运行不同的命令?

java - JCheckBox 未出现

java - 停止 "javax.swing.timer"不会暂停动画

java - 使用单独的线程更新 JTable

java - 从 Eclipse 为 Nexus 部署典型的 Maven 插件

java - 定义一个 swig 接口(interface)文件,用于从某个头文件生成每种类型的包装器

android - 为什么这个处理程序(可运行)在服务上启动时会减慢我的应用程序?

java - 我应该如何访问 ThreadPoolExecutor 中 beforeExecute 和 afterExecute Hook 中的类成员?

java - 从 Java 打印到喷墨的速度非常慢

java - 如何在Eclipse中打开gwt设计器?