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



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

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

那么在哪种情况下我们应该在局部变量上同步呢?

您正在谈论以下情况:

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 内存模型中,对象位于堆中(即使引用是存在于堆栈中的线程的本地引用),同步就是一次仅通过一个线程限制对堆上对象的访问

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

有两种情况:

  1. 局部变量是基元类型,如intdouble
  2. 局部变量的引用类型类似于ArrayList

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

在第二种情况下,这完全取决于局部变量指向什么。如果它指向其他线程 (can) 也指向的对象,则需要确保代码正确同步。

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

但是,如果对象是在线程中创建的,并且只分配给该局部变量,并且您从未从线程向另一个线程提供对它的引用,并且对象实现本身也没有给出引用,则无需担心同步。

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

因此:如果您需要同步,它总是关于多个线程。当然,然后您需要锁定所有这些线程都可以访问的内容。

或者换句话说:锁上门以防止自己进入建筑物是没有意义的。

但是,正如另一个答案所指出的:它实际上取决于"局部"变量的定义。假设您有:

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

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

是的,当使用局部变量来同步从与局部变量相同的方法定义和创建的线程对代码块的访问时,这确实有意义。

最新更新