我想知道一个类的每个实例是否都有该类中方法的副本?
让我们说,我有以下课程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
运算符获取实例时,我无法理解为什么会这样?
答案 0 :(得分:14)
每个对象都有自己的类实例变量副本 - 它是static
个变量,它们在类的所有实例之间共享。实例变量不一定是线程安全的原因是它们可能被多个调用非同步实例方法的线程同时修改。
class Example {
private int instanceVariable = 0;
public void increment() {
instanceVariable++;
}
}
现在,如果两个不同的线程同时调用increment
,那么您将获得数据竞争 - instanceVariable
可能会在返回的两个方法结束时递增1或2。您可以通过将synchronized
关键字添加到increment
,或使用AtomicInteger
而不是int
等来消除此数据竞争,但重点是因为每个对象获取它自己的类的实例变量副本并不一定意味着以线程安全的方式访问变量 - 这取决于类的方法。 (异常是final
不可变变量,不能以线程不安全的方式访问,缺少像序列化黑客那样的傻瓜。)
答案 1 :(得分:7)
多线程问题主要出现在静态变量和同时访问类的实例中。
您不应该担心课程中的方法,而应该更多地关注字段(意味着在课程级别作用域)。如果存在对类实例的多个引用,则不同的执行路径可能会同时尝试访问该实例,从而导致意外后果,例如竞争条件。
一个类基本上是制作一个对象实例的蓝图。当对象被实例化时,它接收内存中由引用访问的点。如果多个线程具有此引用的句柄,则可能导致同时访问实例的情况,这将导致两个线程都操纵字段。
答案 2 :(得分:7)
'实例变量不是线程安全' - 此语句取决于上下文。 确实,如果你在谈论Servlets。这是因为,Servlets只创建一个实例,多个线程访问它。因此,在这种情况下,Instance Variables不是线程安全的。
在上面简化的情况下,如果要为每个线程创建新实例,那么您的实例变量是线程安全的。
希望这能回答你的问题
答案 3 :(得分:5)
method
只是一组指令。无论哪个线程调用该方法,都要获取这些指令的副本。之后执行开始。该方法可以使用method and thread-scoped
的局部变量,也可以使用共享资源,如静态资源,共享对象或其他资源,visible across threads
。
答案 4 :(得分:2)
在许多情况下,可以从多个类访问实例。例如,如果您的实例是另一个类中的静态变量,那么所有线程都将共享该实例,并且您可以通过这种方式遇到大麻烦。这只是我想到的第一种方式......
答案 5 :(得分: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
,则可以引用另一个实例的变量。这就是你在多线程程序中遇到麻烦的方法。但是,只要一个对象不会从一个线程“逃逸”到其他人可见,就没有什么可担心的。