首页 文章

实例变量的实例方法和线程安全性

提问于
浏览
18

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

可以说,我有以下课程 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 运算符获取实例时,我不明白为什么它应该是这样的?

6 回答

  • 4

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

    class Example {
        private int instanceVariable = 0;
    
        public void increment() {
            instanceVariable++;
        }
    }
    

    现在,如果两个不同的线程同时调用 increment ,那么您将获得数据竞争 - 在返回的两个方法结束时, instanceVariable 可能会增加1或2 . 您可以通过将 synchronized 关键字添加到 increment ,或使用 AtomicInteger 而不是 int 等来消除此数据竞争,但关键是因为每个对象都获得了自己的类's instance variables does not necessarily mean that the variables are accessed in a thread-safe manner - this depends on the class'方法的副本 . (例外是 final 不可变变量,不能以线程不安全的方式访问,缺少像序列化黑客那样愚蠢的东西 . )

  • 13

    '实例变量不是线程安全' - 此语句取决于上下文 . 确实,如果你在谈论Servlets . 这是因为,Servlets只创建一个实例,多个线程访问它 . 因此,在这种情况下,Instance Variables不是线程安全的 .

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

    希望这能回答你的问题

  • 2

    每个实例都有自己的一组实例变量 . 您如何检测每个实例是否都有方法的独特“副本”?仅通过检查实例变量的状态,这些差异是否可见?

    实际上,不,该方法只有一个副本,这意味着在调用该方法时执行的指令集 . 但是,在执行时,实例方法可以引用使用保留标识符 this 调用它的实例 . this 标识符引用当前实例 . 如果您没有使用其他内容限定实例变量(或方法),则隐含 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 是隐含的非限定变量,所以您可以删除示例中对 this 的所有引用,它仍将完全相同 .

    但是,如果变量是合格的,如上面的 friend.flag ,则可以引用另一个实例的变量 . 这就是你在多线程程序中遇到麻烦的方法 . 但是,只要一个物体没有什么可担心的 .

  • 2

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

  • 7

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

  • 5

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

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

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

相关问题