我想知道我是否使用正确的方法在不同的线程中调用某些东西。 我是在 Android 上做的,但认为这是一般的 Java 问题。
我有一些参数的方法。假设它们是整数。
class Main1 {
public static void mainOnlyWork(int x, int y) {
// not important here.
}
}
class Test {
Handler mHandler;
// called from main thread, stored as reference.
public Test() {
mHandler = new Handler();
}
public static void callInMainThread(final int x, final int y) {
mHandler.post(new Runnable() {
public void run() {
Main1.mainOnlyWork(x, y);
}
});
}
现在我的问题是,使用 final int 来创建没有任何类成员的匿名 runnable 是否安全?如果我省略 x 和 y 参数的 final 关键字,Eclipse 会报错。在我看来,这是为了在这种情况下只使用常量。如果我传递的不是常数,可以吗? Java 会通过传递给这个函数来“使”它保持常量吗?
但我想使用 JNI 从 native 调用 Test.callInMainThread。在我看来,Java 无法判断这些数字是否为常量。我可以相信 Java 会创造一些奇迹吗?它会一直这样吗?
我想也许我必须创建代理类,例如:
private abstract RunnableXY implements Runnable {
public RunnableXY(int x, int y) {
this.x = x;
this.y = y;
}
public int x;
public int y;
public abstract void run();
}
调用方法将使用:
public static void callInMainThread(final int x, final int y) {
mHandler.post(new RunnableXY(x,y) {
public void run() {
Main1.mainOnlyWork(this.x, this.y);
}
});
}
通过这种方式,我可以保护值免受垃圾收集,直到使用并丢弃 runnable。我是否必须创建包装器,或者在方法参数中标记 final x 是否安全?当我尝试时,final 关键字工作得很好。但是在线程中,我不认为它现在是否有效是它永远有效的原因。它总是与 final 一起工作吗?如果有的话是怎么做出来的?如果参数不是原始类型,而是对象,会有区别吗?
更新: 我已经了解 final 在 Java 中的含义。这不是问题所在。问题点是在创建 Runnable 时使用的变量范围在哪里。它们是局部变量,这意味着在函数结束后无法引用它们的值。当 Runnable 对象被传递给其他线程并等待执行时,这些值存储在哪里?
最佳答案
在线程内部获取参数和局部变量(驻留在方法调用堆栈上)的副本。这是因为在方法调用完成后,线程仍然存在。
并且要求变量是final的,禁止在方法中覆盖原来的变量,导致线程中有不同的版本。这简直是误导。因此,让同名的两个版本表示同一事物是一个问题。
精心的语言设计。
(稍微简化,不命名对称颠倒的情况,同样成立。)
关于java - 匿名 Runnable 中使用的最终 int 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17812498/