【问题标题】:How to capture enclosing scope in Runnable如何在 Runnable 中捕获封闭范围
【发布时间】:2016-04-17 18:00:14
【问题描述】:

我正在尝试使用下面的类对HandlerThread 进行更新流,但我有几个关于变量捕获在 Java 中的工作原理的问题。

[1] ret 是否通过引用从封闭范围中捕获?

[2] this 是指Runnable,还是从封闭范围捕获的?

[奖励] StartStream 应该将Runnable 发布到处理程序线程,并且仅在Runnable 完成时返回。下面的代码会按预期工作吗?

public class Stream extends HandlerThread {
    Handler handler = null;

    Stream() {
        super("Stream");
        handler = new Handler(getLooper());
        start();
    }

    private int _startStream() { // Start some repeating update
        return 1;
    }

    public int StartStream() {
        int ret = -1;

        handler.post(new Runnable(){
            @Override public void run() {
                synchronized(this) {
                    ret = _startStream();    // [1]
                    this.notify();           // [2]
                }
            }
        });

        synchronized(this) {
            while(ret == -1) {
                try {
                    this.wait();
                }
                catch (InterruptedException e){}
            }
        }

        return ret;
    }
}

【问题讨论】:

  • 你为什么要扩展HandlerThread
  • 因为HandlerThread 被设计为直接使用
  • 写它的人
  • 该课程没有被标记为最终课程,并且来源包含有关如果要扩展课程该怎么做的 cmets...所以您必须原谅我无视您的评论。跨度>
  • 确保它不是最终的,有经验的用户可以扩展它并覆盖onLooperPrepared,例如,确保它们也覆盖其他方法,但不是以你正在做的方式,请参阅:androidxref.com/6.0.1_r10/…,超过 9 / 10 的案例是直接使用 HandlerThread

标签: java android multithreading


【解决方案1】:

内部类有对外部类的隐式引用。

要在匿名内部类中使用ret,它应该是最终的。局部变量不能作为非final引用的原因是方法返回后局部类实例可以保留在内存中。它还取决于java version。它仍然应该是“有效的最终”或将其移至成员变量。

this 指的是Runnable,你应该使用Stream.this 括起来。

【讨论】:

  • 我不明白你所说的“ret”是什么意思。我需要在 Runnable 的封闭范围内设置一个变量/标志。将“ret”设为最终/只读是如何实现的?
  • 你的意思是局部变量会被自动捕获为 final 作为安全机制,因为它们可能会超出范围?
  • 你应该添加 final 以满足编译器
  • 但是(final == readonly)对吗?那么下面的 while() 循环如何知道变量何时发生了变化?
  • 局部变量不能作为非final引用的原因是方法返回后局部类实例可以保留在内存中。
【解决方案2】:

ret 是一个局部变量,因此需要是有效的最终变量。这意味着,如果 ret 在初始化后被分配给另一个值,编译器会抱怨。因此 [1] 会导致编译器错误。

这是因为 Java 语言架构师希望防止局部变量(在方法中声明的变量)从声明它的方法之外的其他地方更改。

有关从封闭方法捕获变量的更多信息:

this 确实指的是Runnable 实例。但是,您可以使用 Stream.this 来引用封闭的 Stream 实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    相关资源
    最近更新 更多