如果我有一个对象A的实例,它有一个实例方法foo(),该方法中只创建和使用变量,那么即使同一实例被多个线程访问,该方法也是线程安全的吗?
如果是,如果对象A上的实例方法bar()在上述文本中创建了许多线程并调用方法foo(),这是否仍然适用?
这是否意味着每个线程都获得了该方法的“副本”,即使它属于同一个实例?
我故意不使用synchronized关键字。
谢啦
对所有局部变量(方法中定义的变量)都将位于它们自己的堆栈框架中。因此,只要引用没有脱离作用域(方法),它们将是线程安全的
注意:如果本地引用转义了该方法(作为另一个方法的参数),或者某个方法在某些类级或实例级字段上工作,那么它不是线程安全的。
这是否意味着即使每个线程属于同一个实例,也会得到该方法的“副本”
不,只会有一个方法,每个线程共享相同的方法。但是每个线程都有自己的堆栈框架,局部变量将在该线程的堆栈框架上。即使您在本地对象上使用同步,Escape Analysis也证明JVM将优化您的代码并删除所有类型的同步。
例如:
public static void main(String[] args) {
Object lock = new Object();
synchronized (lock) {
System.out.println("hello");
}
}
将有效地转换为:
public static void main(String[] args) {
Object lock = new Object(); // JVm might as well remove this line as unused Object or instantiate this on the stack
System.out.println("hello");
}
您必须将正在运行的代码和正在处理的数据分开。
该方法是由每个线程执行的代码。如果该代码包含一条语句,如inti=5
,该语句定义了一个新变量i,并将其值设置为5,则每个线程将创建该变量。
多线程的问题不在于公共代码,而在于公共数据(和其他公共资源)。如果公共代码访问在别处创建的某个变量j
,则所有线程将访问相同的变量j
,即相同的数据。如果其中一个线程在其他线程读取时修改共享数据,则可能会发生各种错误。
现在,关于您的问题,只要您的变量在bar()中定义,并且bar()不访问某些公共资源(如文件),那么您的代码就应该是线程安全的。
您应该发布一些示例代码,以确保我们理解用例。
对于此示例:
public class Test {
private String varA;
public void doSomething() {
String varB;
}
}
如果在本例中不修改varA
,而只修改varB
,则本例是线程安全的。
但是,如果创建或修改varA
并依赖于它的状态,则该方法不是线程安全的。