25

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

可以说,我有以下课程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

4

6 回答 6

20

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

class Example {
    private int instanceVariable = 0;

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

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

于 2013-07-26T16:16:36.783 回答
11

“实例变量不是线程安全的” - 此语句取决于上下文。这是真的,例如,如果您正在谈论 Servlet。这是因为,Servlet 只创建一个实例,多个线程访问它。所以在那种情况下,实例变量不是线程安全的。

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

希望这能回答你的问题

于 2013-07-26T16:26:30.920 回答
11

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

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

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

于 2013-07-26T16:18:49.207 回答
6

Amethod只不过是一组指令。无论哪个线程调用该方法,都会获取这些指令的副本。之后执行开始。该方法可以使用局部变量,method and thread-scoped也可以使用共享资源,如静态资源、共享对象或其他资源,它们是visible across threads

于 2013-07-26T16:30:34.410 回答
5

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

实际上,不,该方法只有一个副本,这意味着调用该方法时执行的一组指令。但是,在执行时,实例方法可以使用保留的标识符引用正在调用它的实例thisthis标识符指的是当前实例。如果您没有用其他东西限定实例变量(或方法),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()构成andsetAnotherFlag()方法的 VM 指令的字节只有一份副本。但是当它们被调用时,this被设置为调用发生的实例。因为this是对非限定变量隐含的,您可以删除this示例中对的所有引用,它的功能仍然完全相同。

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

于 2013-07-26T16:28:32.587 回答
1

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

于 2013-07-26T16:15:20.570 回答