【问题标题】:Local Variable in Static Inner Class静态内部类中的局部变量
【发布时间】:2021-11-02 06:25:25
【问题描述】:

假设我有以下内部类,现在 method1() 被 2 个线程访问,比如线程 1 和线程 2,这里我们声明一个局部变量并递增它。 现在这个局部变量是原始数据类型并且将存在于堆栈中,因为每个线程都有自己的内存堆栈,它不应该在线程之间共享,但是 int local 也是静态内部类的一部分,所以我想知道int local 是否会在线程之间共享?

如果2个线程同时调用method1(),内存分配会怎样?

private static class SharedClass {
        int a = 0;
 
        public void method1() {
            int local = 0;
            local++;
            a=local;
        }     
   }

【问题讨论】:

  • int local 不是SharedClass成员
  • 所以如果我同时调用 SharedClass.method1() 2 次,两个线程将拥有自己的 int local 副本,对吗?
  • 本质上是的。
  • 但是,如果两个线程都在 SharedClass 的同一个实例上调用 method1a 可能是共享的。

标签: java multithreading stack static-classes


【解决方案1】:

局部变量永远不会与 Java 中的其他线程共享。我们谈论的是普通方法还是 lambdas 都没关系。不管方法是在顶级类、内部类、嵌套类、匿名类还是本地类中声明。

因此,在您的示例中,两个线程将拥有自己的 local 变量副本,但它们可能正在更新共享的 a 变量...取决于哪个 SharedClass例如,他们正在调用该方法。

或者,换句话说,您无需担心local = 0;local++ 的线程安全,但您需要担心aa=local; 分配的访问权限。


在某些情况下,局部变量似乎被共享。然而,这是一种错觉。考虑一下:

public void test() {
    final int arg = 42;
    new Thread(new Runnable(){
        public void run() {
            System.out.println(arg);
        }
    }).start();
}

看起来arg 变量被子线程访问。但实际上子线程实际访问的将是Runnable实例中的一个合成变量,其值已经被初始化为arg的值;即42

(如果你编译上面的代码并使用javap检查字节码,你会看到它是如何工作的。)

请注意,只有当argfinal实际上是最终的 时,Java 编译器才允许这样做。如果不是final实际上是最终的,那么使用合成变量的技巧将不起作用。

【讨论】:

  • 我理解了局部变量部分,但是为什么我需要担心a=local;的赋值,那不是原子操作吗?
  • 它是原子的。但是,Java 内存模型表示,一个线程对a 所做的更改不能保证对另一个线程可见。访问/更新应该使用synchronized,或者a应该声明为volatile
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-02
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
相关资源
最近更新 更多