Java 局部变量中引用的实例变量。内存、线程安全和终结

Java Instance Variable referred within local variable. Memory, thread safety and finalization

我有 class MyClass,它有一个带有变量的方法 - OtherClass 的一个实例,如下所示

public class Myclass{ 
   public void meth1(){
 
  OtherClass other = new OtherClass();  
    other.perform();
     
    }

}

public class OtherClass{

private Map<String, String> ops = new HashMap<>();

public void perform(){

  // put/ remove values in ops 
    }

} 

这是一个多线程环境 当一个线程执行 meth1() 方法时,Map 是在哪里创建的?在堆?声明为实例变量的映射是否存在线程安全问题。 当局部变量被垃圾回收时,我假设 map 也被垃圾回收。如果我错了,请纠正。

注意:我知道在多线程环境中有实例变量时会出现数据损坏 然而,这是略有不同的情况[​​=12=]

OtherClass 对象将在堆上创建,并且对该对象的引用将在堆栈上创建。由于 stack confinement,这段代码是完全线程安全的。只有当对象的状态在多个线程之间共享时,才会出现线程安全问题。由于此对象只能由调用该方法的线程访问,因此它不是共享的。一旦堆栈弹出,对象将被垃圾回收。

When a thread executes the method meth1() where does Map is created? in heap?

是的。你用 new Whatever() 创建的所有东西都存储在堆上,包括 OtherClass 实例和它的 HashMap (因为它的初始化包括 new HashMap<>() 表达式)。每次执行 new Whatever() 时,您都会在堆上获得一个全新的实例。

Is there thread safety issues wrt to the map declared as instance variable.

不,在你的例子中不是。仅当多个线程访问 OtherClass 的同一个实例时,线程安全才可能成为问题。在您的情况下,每个执行线程都会创建其单独的 OtherClass 实例(在局部变量 other 中),仅使用该实例,并且不会将其分发到其他线程可能看到它的任何地方。

When local variable is garbage collected, I assume map is also garbage collected.

可以,只要您不添加将地图分发给软件其他部分的代码。

当实例不再被任何 "live" variable/parameter/object/... 引用时,实例将被垃圾回收...在您的情况下,ops HashMap 仅被引用(存储) ops 其封闭 OtherClass 实例的字段。因此,当此实例不再可访问时,Map 也将变得不可访问,从而准备好进行垃圾收集。

一句话:垃圾收集不会在某些东西变得不可访问的同一时刻发生,它是由一些精心设计的优化算法安排的。您唯一可以确定的是,它会在您 运行 内存不足之前发生。

Note: I know there are data corruption when we have instance variables within multi-threaded environment However this is slightly difference scenario

只有相反的方向才是正确的:如果没有实例或 class 字段,则无法 运行 进入线程安全/数据损坏问题。

正确的是:如果在多线程设置中使用实例或class字段,则必须小心。但是例如只读实例字段(仅在构造函数中设置且以后永远不会更改的字段)通常是安全的。