【问题标题】:Using final variables in anonymous threads在匿名线程中使用最终变量
【发布时间】:2018-06-25 20:51:16
【问题描述】:

这样做安全吗

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% 的感觉这是不可能的,但我不知道匿名类如何存储变量,所以我不能 100% 确定。

如果 anon 类要引用该变量的外部引用,那将是错误的,但它不是真正的引用,因为它是一个原始类型。那么线程 anon 类到底是如何存储变量的?

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

【问题讨论】:

  • 它被捕获并存储在 Runnable 对象上。它不能改变。
  • 很好,但是 JVM 是否隐含地为 Runnable 创建了一个构造函数?
  • 它在后台创建了一个字段。我看不出构造函数与它有什么关系。
  • 嗯,好吧,我猜它不需要构造函数,因为在类中你可以执行“final int finalI = someNum”而不是执行“final int finalI;然后在构造函数中设置它”
  • 我如何接受评论作为答案?

标签: java multithreading concurrency thread-safety visibility


【解决方案1】:

final我会分别看到0..9。

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

最终

会。

让我们来

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 int finalI = i;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2021-06-08
    • 1970-01-01
    相关资源
    最近更新 更多