在局部变量上同步是否合理?
Is it reasonable to synchronize on a local variable?
从Java内存模型得知,每个线程都有自己的线程栈,局部变量放在每个线程自己的线程栈中。
并且 其他 线程无法访问这些局部变量。
那么在什么情况下我们应该同步局部变量?
重点是:同步是有目的的。您使用它来确保恰好 一个线程可以在任何给定时间执行一些特殊的值得保护的activity。
因此:如果您需要同步,它总是比一个线程多。当然,然后您需要锁定 所有 这些线程可以访问的内容。
或者换句话说:你锁门以防止你自己进入大楼是没有意义的。
但是,正如另一个答案所指出的:它实际上取决于 "local" 变量的定义。假设您有:
void foo() {
final Object lock = new Object();
Thread a = new Thread() { uses lock
Thread b = new Thread() { uses lock
那么可以肯定的是,"local" 变量可以用作这两个线程的锁。除此之外:该示例之所以有效,是因为同步发生在特定对象的 monitor 上。对象驻留在堆上。全部。
是的,当局部变量用于同步访问来自线程的代码块时,它确实有意义,这些线程是在与局部变量相同的方法中定义和创建的。
有两种情况:
- 局部变量是原始类型,如
int
或double
。
- 局部变量是引用类型,如
ArrayList
。
在第一种情况下,您不能同步,因为您只能同步对象(由引用类型变量指向)。
第二种情况,全看局部变量指向什么。如果它指向其他线程(也可以)也指向的对象,那么您需要确保您的代码已正确同步。
示例:您从 static
或实例字段分配局部变量,或者从共享集合中获取对象。
但是,如果该对象是在您的线程中创建的,并且只分配给该局部变量,并且您从不将对它的引用从您的线程提供给另一个线程,并且对象实现本身也没有提供out 引用,那么你就不用担心同步问题了。
您说的是以下案例:
public class MyClass {
public void myMethod() {
//Assume Customer is a Class
Customer customer = getMyCustomer();
synchronized(customer) {
//only one thread at a time can access customer object
which ever holds the lock
}
}
}
在上面的代码中,customer
是一个局部引用变量,但是你还在使用同步块来限制对对象customer
的访问指向(一次一个线程)。
在 Java 内存模型中,对象存在于堆中(即使引用对于存在于堆栈中的线程而言是本地的)并且同步就是限制对对象的访问heap 一次恰好一个线程。
简而言之,当你说局部变量(非原始)时,只有引用是局部的,而不是实际对象本身,即它实际上是指堆上的一个对象 可以被许多其他线程访问。因此,您需要对对象进行同步,以便单个线程一次只能访问该对象。
从Java内存模型得知,每个线程都有自己的线程栈,局部变量放在每个线程自己的线程栈中。
并且 其他 线程无法访问这些局部变量。
那么在什么情况下我们应该同步局部变量?
重点是:同步是有目的的。您使用它来确保恰好 一个线程可以在任何给定时间执行一些特殊的值得保护的activity。
因此:如果您需要同步,它总是比一个线程多。当然,然后您需要锁定 所有 这些线程可以访问的内容。
或者换句话说:你锁门以防止你自己进入大楼是没有意义的。
但是,正如另一个答案所指出的:它实际上取决于 "local" 变量的定义。假设您有:
void foo() {
final Object lock = new Object();
Thread a = new Thread() { uses lock
Thread b = new Thread() { uses lock
那么可以肯定的是,"local" 变量可以用作这两个线程的锁。除此之外:该示例之所以有效,是因为同步发生在特定对象的 monitor 上。对象驻留在堆上。全部。
是的,当局部变量用于同步访问来自线程的代码块时,它确实有意义,这些线程是在与局部变量相同的方法中定义和创建的。
有两种情况:
- 局部变量是原始类型,如
int
或double
。 - 局部变量是引用类型,如
ArrayList
。
在第一种情况下,您不能同步,因为您只能同步对象(由引用类型变量指向)。
第二种情况,全看局部变量指向什么。如果它指向其他线程(也可以)也指向的对象,那么您需要确保您的代码已正确同步。
示例:您从 static
或实例字段分配局部变量,或者从共享集合中获取对象。
但是,如果该对象是在您的线程中创建的,并且只分配给该局部变量,并且您从不将对它的引用从您的线程提供给另一个线程,并且对象实现本身也没有提供out 引用,那么你就不用担心同步问题了。
您说的是以下案例:
public class MyClass {
public void myMethod() {
//Assume Customer is a Class
Customer customer = getMyCustomer();
synchronized(customer) {
//only one thread at a time can access customer object
which ever holds the lock
}
}
}
在上面的代码中,customer
是一个局部引用变量,但是你还在使用同步块来限制对对象customer
的访问指向(一次一个线程)。
在 Java 内存模型中,对象存在于堆中(即使引用对于存在于堆栈中的线程而言是本地的)并且同步就是限制对对象的访问heap 一次恰好一个线程。
简而言之,当你说局部变量(非原始)时,只有引用是局部的,而不是实际对象本身,即它实际上是指堆上的一个对象 可以被许多其他线程访问。因此,您需要对对象进行同步,以便单个线程一次只能访问该对象。