Java 实例方法与实例变量的线程安全

Java 实例方法与实例变量的线程安全,java,multithreading,Java,Multithreading,我想知道一个类的每个实例是否都有该类中方法的副本 比如说,我有下面的类MyClass: public MyClass { private String s1; private String s2; private String method1(String s1){ ... } private String method2(String s2){ ... } } 因此,如果两个不同的用户创建了MyClass的实例,比如:

我想知道一个类的每个实例是否都有该类中方法的副本

比如说,我有下面的类
MyClass

public MyClass {

    private String s1;

    private String s2; 

    private String method1(String s1){
    ...
    }

    private String method2(String s2){
    ...
    }
}
因此,如果两个不同的用户创建了
MyClass
的实例,比如:

MyClass instanceOfUser1 = new MyClass();
MyClass instanceOfUser2 = new MyClass();
知道每个用户的线程中都有
MyClass
方法的副本吗?如果是,那么实例变量是线程安全的,只要只有实例方法操作它们,对吗


我问这个问题是因为我经常读到实例变量不是线程安全的。我不明白为什么会是这样,当每个用户通过调用
new
操作符获得一个实例时?

在许多情况下,一个实例可以从多个类访问。例如,如果您的实例是另一个类中的静态变量,那么所有线程都将共享该实例,这样您可能会遇到大麻烦。这只是我想到的第一种方法…

每个对象都有自己的类实例变量副本-它是类的所有实例之间共享的
静态变量。实例变量不一定是线程安全的原因是,它们可能会被调用非同步实例方法的多个线程同时修改

class Example {
    private int instanceVariable = 0;

    public void increment() {
        instanceVariable++;
    }
}

现在,如果两个不同的线程同时调用
increment
,那么您就有了一个数据竞争-
instanceVariable
可能会在两个方法返回的末尾增加1或2。您可以通过将
synchronized
关键字添加到
increment
,或使用
AtomicInteger
而不是
int
等来消除这种数据竞争,但关键是,仅仅因为每个对象都有自己的类实例变量副本,并不一定意味着变量是以线程安全的方式访问的——这取决于类的方法。(例外情况是
final
不可变变量,不能以线程不安全的方式访问,除非是像序列化黑客这样愚蠢的东西。)

多线程问题主要出现在同时访问静态变量和类的实例时

您不应该担心类中的方法,而应该更多地关注字段(这意味着在类级别定义了范围)。如果存在对一个类实例的多个引用,则不同的执行路径可能会尝试同时访问该实例,从而导致意外后果,如竞争条件


类基本上是创建对象实例的蓝图。当对象被实例化时,它在内存中接收一个由引用访问的点。如果有多个线程具有此引用的句柄,则可能会导致同时访问实例的情况发生,这将导致两个线程操作字段。

'instance Variables not thread safe'-此语句取决于上下文。 这是真的,如果你说的是servlet。这是因为,servlet只创建一个实例,多个线程访问它。因此,在这种情况下,实例变量不是线程安全的

在上述简化的情况下,如果要为每个线程创建新实例,那么实例变量是线程安全的


希望这能回答您的问题

每个实例都有自己的实例变量集。您将如何检测每个实例是否都有不同的方法“副本”?只有通过检查实例变量的状态才能看到差异吗

事实上,没有,只有一个方法副本,这意味着调用该方法时执行的指令集。但是,在执行时,实例方法可以引用正在使用保留标识符
this
调用它的实例。
标识符引用当前实例。如果您不使用其他内容限定实例变量(或方法),则暗示此

比如说,

final class Example {

  private boolean flag;

  public void setFlag(boolean value) {
    this.flag = value;
  }

  public void setAnotherFlag(Example friend) {
    friend.flag = this.flag;
  }

}
对于
setFlag()
setAnotherFlag()
方法,只有一个字节副本构成VM指令。但是当调用它们时,
这个
被设置为发生调用的实例。因为
this
是针对非限定变量的,所以您可以删除示例中对
this
的所有引用,并且它的功能仍然完全相同


但是,如果一个变量是限定的,比如上面的
friend.flag
,则可以引用另一个实例的变量。这就是在多线程程序中遇到麻烦的原因。但是,只要一个对象没有从一个线程“逃逸”到其他线程可见,就没有什么可担心的。

A
方法
只不过是一组指令。无论哪个线程调用该方法,都要获取这些指令的副本。然后开始执行。该方法可以使用
方法和线程范围的局部变量
,也可以使用共享资源,如静态资源、共享对象或其他资源,哪些是线程间可见的

您是在询问每个线程都有自己的
MyClass
实例,还是每个线程都有一个方法不同的
MyClass
实例?没有实例变量本质上是线程安全的。如果两个线程可以修改对同一对象的引用,那么您需要实现某种类型的同步。您真的很困惑。线程安全与状态有关。状态是关于字段的,而不是关于方法的。类的线程安全性完全取决于方法如何使用字段s1和s2。没有它们的主体使问题无法回答。使MyClass不可变当然意味着这个问题不会出现。我问这个问题是因为我经常读到实例变量不是线程安全的。因为你的问题是