【问题标题】:Accumulative Runnable in Swing JavaSwing Java 中的累积可运行对象
【发布时间】:2020-06-05 23:28:54
【问题描述】:

作为学习 SwingWorker 的一部分,我正在查看源代码,其中我注意到了一个叫做 AccumulativeRunnable 的东西。从 AccumulativeRunnable 类定义的注释中,我了解何时使用它,但是当我检查示例代码时,我的脑海中浮现了几个问题。

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

一个抽象类(AccumulativeRunnable),用于我们需要对一组可附加数据执行某些操作的情况。
发送后可能会附加该组数据 执行。通常这样的 Runnables 被发送到 美国东部时间。

使用示例:假设我们要实现 JLabel.setText(String text) 它将字符串发送到 EDT 上的 JLabel.setTextImpl(String text)。 如果 JLabel.setText 在 EDT 之外被多次快速调用 我们将在 EDT 上获得许多更新,但只有最后一个是 重要的。 (每次下一次更新都会覆盖前一次。)我们可能会 想要以只有最后一次更新的方式实现这一点 已送达。

  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 接口。
  2. 为什么 AccumulativeRunnable 类的add() 方法是 synchronized ?.有人可以用一个简单的例子来解释这个吗? 以我上面提供的示例为例。
  3. arguments里面的add()方法 AccumulativeRunnable 类将是 null ?有人可以用一个简单的例子来解释这个吗? 以我上面提供的示例为例。
  4. add() 方法如何接收数组 (T...args) ?有人可以 用一个简单的例子或我提供的例子来解释这个 以上。
  5. 在上面的例子中当我们调用doSetTextImpl.add(text);它 调用 AccumulativeRunnable 类的add() 方法。但这怎么 内部调用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;
    }
}

【问题讨论】:

    标签: java swing runnable swingworker swingx


    【解决方案1】:
    1. 答案是Runnable.run() 的以下实现。在 Compiler 看来,run(List&lt;T&gt;) 与接口声明的方法无关,它只是一个(巧合)同名的不同方法。

      公共最终无效运行(){ 运行(冲洗()); }

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

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

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

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

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

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

    5. 答案写在您提供的报价中:

      通常此类 Runnable 会发送到 EDT。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多