Java 中的并发:同步静态方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5443297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Concurrency in Java: synchronized static methods
提问by Amir Rachum
I want to understand how locking is done on static methods in Java.
我想了解如何锁定 Java 中的静态方法。
let's say I have the following class:
假设我有以下课程:
class Foo {
private static int bar = 0;
public static synchronized void inc() { bar++; }
public synchronized int get() { return bar; }
It's my understanding that when I call f.get()
, the thread acquires the lock on the object f
and when I do Foo.inc()
the thread acquires the lock on the class Foo
.
这是我的理解是,当我打电话f.get()
,线程获取对象的锁f
,当我做Foo.inc()
了线程获取类上的锁Foo
。
My question is how are the two calls synchronized in respect to each other? Is calling a static method also acquires a lock on all instantiations, or the other way around (which seems more reasonable)?
我的问题是这两个调用如何相互同步?调用静态方法是否也会获得对所有实例的锁定,或者相反(这似乎更合理)?
EDIT:
编辑:
My question isn't exactly how static synchronized
works, but how does static and non-static methods are synchronized with each other.
i.e., I don't want two threads to simultaneously call both f.get()
and Foo.inc()
, but these methods acquire different locks. My question is how is this preventable and is it prevented in the above code.
我的问题不完全是如何static synchronized
工作,而是静态和非静态方法如何相互同步。即,我不希望两个线程同时调用f.get()
and Foo.inc()
,但这些方法获取不同的锁。我的问题是如何避免这种情况,以及在上面的代码中是否可以防止这种情况发生。
采纳答案by axtavt
Static and instance synchronized
methods are not related to each other, therefore you need to apply some additional synchronization between them, like this:
静态synchronized
方法和实例方法彼此不相关,因此您需要在它们之间应用一些额外的同步,如下所示:
class Foo {
private static int bar = 0;
public static synchronized void inc() { bar++; }
public synchronized int get() {
synchronized (Foo.class) { // Synchronizes with static synchronized methods
return bar;
}
}
}
(though in this case leaving synchronized
on get()
doesn't make sense, since it doesn't do anything that requires synchronization on instance).
(尽管在这种情况下,留下synchronized
的get()
没有任何意义,因为它没有做任何事情需要在实例同步)。
Beware of deadlocks - since this code aquires multiple locks, it should do it in consistent order, i.e. other synchronized static methods shouldn't try to acquire instance locks.
谨防死锁 - 由于此代码获取多个锁,因此应以一致的顺序执行,即其他同步静态方法不应尝试获取实例锁。
Also note that this particular task can be solved without synchronization at all, using atomic fields:
另请注意,使用原子字段可以完全不同步地解决此特定任务:
class Foo {
private static AtomicInteger bar = new AtomicInteger(0);
public static void inc() { bar.getAndIncrement(); }
public int get() { return bar.get(); }
}
回答by Jon Skeet
A synchronized static method is effectively equivalent to:
同步静态方法实际上等效于:
public static void foo() {
synchronized (ClassName.class) {
// Body
}
}
In other words, it locks on the Class
object associated with the class declaring the method.
换句话说,它锁定Class
与声明方法的类关联的对象。
From section 8.4.3.6 of the JLS:
A synchronized method acquires a monitor (§17.1) before it executes. For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
同步方法在执行之前获取监视器(第 17.1 节)。对于类(静态)方法,使用与方法类的 Class 对象关联的监视器。对于实例方法,使用与 this(调用方法的对象)关联的监视器。
回答by bmargulies
If you read http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html.
如果您阅读http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html。
It will tell you:
它会告诉你:
You might wonder what happens when a static synchronized method is invoked, since a static method is associated with a class, not an object. In this case, the thread acquires the intrinsic lock for the Class object associated with the class. Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class.
您可能想知道调用静态同步方法时会发生什么,因为静态方法与类相关联,而不是与对象相关联。在这种情况下,线程获取与类关联的 Class 对象的内在锁。因此,对类的静态字段的访问是由一个与该类的任何实例的锁不同的锁控制的。
which tells you all you need to know.
它告诉你所有你需要知道的。
回答by Mat
Neither, the non-static synchronized call does not acquire a lock on the class itself. (And the static synchronized block does not lock any object instantiated from that class.)
非静态同步调用也不会获取类本身的锁。(并且静态同步块不会锁定从该类实例化的任何对象。)
In other words the calls f.get()
(locks f
) and Foo.inc()
(locks the class Foo
) can run concurrently. They are not "synchronized".
换句话说,调用f.get()
(locks f
) 和Foo.inc()
(locks the class Foo
) 可以同时运行。它们不是“同步的”。
You could use a different pattern (singleton), or make all the methods static.
您可以使用不同的模式(单例),或将所有方法设为静态。
回答by Johan Sj?berg
Static
locks are attached to the class
definition and thus is shared between all instances of that class.
Static
锁附加到class
定义上,因此在该类的所有实例之间共享。
Synchronization of none static
methods only apply to the current instance of the class (the lock is on the class instance, e.g., this
). In your example you have two different locks with no interrelation.
none static
方法同步仅适用于类的当前实例(锁定在类实例上,例如,this
)。在您的示例中,您有两个没有相互关系的不同锁。
I don't want two threads to simultaneously call both f.get() and Foo.inc(), but these methods acquire different locks. My question is how is this preventable and is it prevented in the above code
我不希望两个线程同时调用 f.get() 和 Foo.inc(),但这些方法获取不同的锁。我的问题是这是如何预防的,是否在上面的代码中被阻止
You mustshare a lock to be able to arbitrate access to both f.get
and Foo.inc()
. You can do this either by sharing the same static lock or by the same instance lock.
您必须共享一个锁才能仲裁对f.get
和 的访问Foo.inc()
。您可以通过共享相同的静态锁或相同的实例锁来做到这一点。
回答by xappymah
These two calls do not synchronize in respect to each other.
It is as you said, a caller of f.get()
acquires the lock of f
object and caller of Foo.inc()
acquires Foo.class
object's one. So the synchronization rules are the same as if instead of static call you called an instance synchronized method with another object.
这两个调用彼此不同步。就像你说的,调用者获取对象的f.get()
锁,f
调用者Foo.inc()
获取Foo.class
对象的锁。因此,同步规则与您使用另一个对象调用实例同步方法而不是静态调用是相同的。