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

问题描述 投票:9回答:4

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

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

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

java multithreading synchronization local-variables
4个回答
22
投票

你在谈论以下案例:

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是一个本地引用变量,但您仍然使用synchronized块来限制对customer指向的对象的访问(一次由一个线程)。

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

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


12
投票

有两种情况:

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

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

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

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

但是,如果对象是在您的线程中创建的并且只分配给该局部变量,并且您从未在线程中向其他线程发出对它的引用,并且对象实现本身也没有给出引用,那么您不需要担心同步。


5
投票

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

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

或者换句话说:为了防止自己进入建筑物,没有必要锁门。

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

void foo() {
  final Object lock = new Object();
  Thread a = new Thread() { uses lock
  Thread b = new Thread() { uses lock

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


2
投票

是的,当局部变量用于同步对来自与本地变量在同一方法中定义和创建的线程的代码块的访问时,它确实有意义。

© www.soinside.com 2019 - 2024. All rights reserved.