在匿名线程中使用最终变量

Using final variables in anonymous threads

做这样的事情安全吗

for (int i = 0; i < 10; i++){
  final int finalI = i;
  new Thread(() -> { 
       // use finalI in the thread somehow
       });
}

那么我想问的问题是,是否保证线程0..9看到finalI分别为0..9?

例如,如果在第二次迭代中更改了 finalI,并且第一个线程看到 finalI 为 1 而不是 0,会怎样。

我有 99% 的感觉这是不可能的,但我不知道匿名 class 是如何存储变量的,所以我不是 100% 确定。

如果 anon class 引用该变量的外部引用,那将是错误的,但它不是真正的引用,因为它是一个原语。那么线程 anon [=23 到底是怎么做的呢? =] 存储变量?

在幕后,JVM 是否让它在匿名线程中给出一个字段 private final int finalI,然后在构造函数中隐式设置它?

最后我会分别看到0..9

要了解内部发生的事情,让我们看看将变量声明为

final

会。

让我们拿

public class ThreadTest {

public static void main(String[] args) {
    for(int i =0; i< 9; i++) {
        final int finalI = i;
        new Thread(()->{
            try {
                Thread.sleep(1000); // assuming a delay for some operations
                System.out.println(Thread.currentThread().getName()+" "+finalI);
                //System.out.println(Thread.currentThread().getName()+" "+ i); // can't do this.
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start(); 

    }
}
}

方法的局部变量保存在栈中,一旦方法结束就会丢失。而 final variables/objects 即使在方法结束后也可以访问本地声明,因为它们被其他 classes/methods 引用,在这种情况下它是可运行的。

所以当我们执行

final int finalI = i;

我们正在创建一个新的 finalI 变量,它既不能改变之前的变量,也不能改变之前的线程使用这个值,因为之前的 finalI 是单独放在 JVM 堆中的。