在局部变量上同步是否合理?

Nin*_*Lee 17 java multithreading synchronization local-variables

从java内存模型中,我们知道每个线程都有自己的线程堆栈,并且局部变量放在每个线程自己的线程堆栈中.

其他线程无法访问这些局部变量.

那么在这种情况下,我们应该同步局部变量?

dev*_*per 28

你在谈论以下案例:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,customer是一个本地引用变量,但您仍然使用synchronized块来限制对象的访问customer(通过一次一个线程).

在Java内存模型中,对象存在于堆中(即使引用对于存在于堆栈中的Thread是本地的),同步也是关于限制一次只有一个线程对堆上对象的访问.

简而言之,当你说局部变量(非原始)时,只有引用是本地的,而不是实际的对象本身,即它实际上是指堆上的一个对象,可以被许多其他线程访问.因此,您需要在对象上进行同步,以便单个线程一次只能访问该对象.

  • 你会在一些 IDE 中看到警告,说局部变量的同步有问题,但这并不是因为它本身就是错误的,而是因为它很容易被搞乱 (5认同)
  • 我对这个解释不是很清楚。比如说,每次调用 getMyCustomer() 都会创建并返回新的 Customer()。现在,当每个线程调用 myMethod() 方法时,引用“customer”将指向内存中的不同对象。在这种情况下,我们是否使同步块内的代码线程安全? (2认同)
  • @SubrataNath getter 方法通常不会创建新对象来返回。 (2认同)

Erw*_*idt 13

有两种情况:

  1. 局部变量是原始类型,如intdouble.
  2. 局部变量的引用类型如ArrayList.

在第一种情况下,您无法进行同步,因为您只能在对象(由引用类型变量指向)上进行同步.

在第二种情况下,这一切都取决于局部变量指向的内容.如果它指向其他线程(可以)指向的对象,则需要确保代码已正确同步.

示例:您从一个static或实例字段分配了局部变量,或者您从共享集合中获取了该对象.

但是,如果对象是在你的线程中创建的,并且只分配给那个局部变量,并且你永远不会从你的线程向另一个线程发出对它的引用,并且对象实现本身也没有给出引用,那么你不需要担心同步.


Gho*_*ica 5

关键是:同步是出于某种目的.您可以使用它来确保在任何给定时间只有一个线程可以执行一些特殊的保护活动.

因此:如果您需要同步,它总是涉及多个线程.当然,那么你需要锁定所有这些线程都可以访问的东西.

或者换句话说:有中没有点,你把门锁上,以防止自己进入建筑物.

但是,正如另一个答案所指出的那样:它实际上取决于"本地"变量的定义.让我们说你有:

void foo() {
  final Object lock = new Object();
  Thread a = new Thread() { uses lock
  Thread b = new Thread() { uses lock
Run Code Online (Sandbox Code Playgroud)

那么肯定的是,"local"变量可以用作这两个线程的锁.除此之外:该示例有效,因为同步发生在特定对象的监视器上.对象驻留在堆上.他们都是.