Java中的并发:同步静态方法

我想了解如何在Java中对静态方法进行锁定。

假设我有以下课程:

class Foo { private static int bar = 0; public static synchronized void inc() { bar++; } public synchronized int get() { return bar; } 

我的理解是,当我调用f.get() ,线程获取对象f的锁定,当我执行Foo.inc() ,线程获取类Foo上的锁。

我的问题是两个呼叫如何相互同步? 调用静态方法也会获取所有实例化的锁定,或者相反(这似乎更合理)?


编辑:

我的问题不是static synchronized工作原理,而是静态和非静态方法如何相互同步。 即,我不希望两个线程同时调用f.get()Foo.inc() ,但这些方法获取不同的锁。 我的问题是这是如何可以预防的,并且在上面的代码中是否被阻止了。

静态和实例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; } } } 

(虽然在这种情况下,在get()上保持synchronized是没有意义的,因为它不会做任何需要在实例上进行同步的事情)。

注意死锁 – 因为这段代码需要多个锁,所以它应该按照一致的顺序执行,即其他同步的静态方法不应该尝试获取实例锁。

另请注意,使用primefaces字段可以在没有同步的情况下解决此特定任务:

 class Foo { private static AtomicInteger bar = new AtomicInteger(0); public static void inc() { bar.getAndIncrement(); } public int get() { return bar.get(); } } 

同步静态方法实际上等同于:

 public static void foo() { synchronized (ClassName.class) { // Body } } 

换句话说,它锁定与声明该方法的Class关联的Class对象。

从JLS第8.4.3.6节开始 :

同步方法在执行之前获取监视器(第17.1节)。 对于类(静态)方法,使用与方法类的Class对象关联的监视器。 对于实例方法,使用与此关联的监视器(调用该方法的对象)。

同样,非静态同步调用不会获取类本身的锁定。 (并且静态同步块不会锁定从该类实例化的任何对象。)

换句话说,调用f.get() (锁定f )和Foo.inc() (锁定类Foo )可以并发运行。 它们不是“同步的”。

您可以使用不同的模式(单例),或使所有方法都是静态的。

如果您阅读http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html 。

它会告诉你:

您可能想知道调用静态同步方法时会发生什么,因为静态方法与类相关联,而不是与对象相关联。 在这种情况下,线程获取与类关联的Class对象的内部锁。 因此,对类的静态字段的访问由一个锁控制,该锁与该类的任何实例的锁不同。

它告诉你所有你需要知道的。

Static锁附加到class定义,因此在class所有实例之间共享。

none static方法的同步仅适用于类的当前实例(锁定在类实例上 ,例如, this )。 在您的示例中,您有两个不同的锁,没有相互关系。

我不希望两个线程同时调用f.get()和Foo.inc(),但这些方法获取不同的锁。 我的问题是这是如何可以预防的,并且在上面的代码中是否被阻止了

必须共享一个锁才能仲裁对f.getFoo.inc() 。 您可以通过共享相同的静态锁或通过相同的实例锁来执行此操作。

这两个调用不会相互同步。 正如你所说, f.get()的调用者获取f对象的锁定和Foo.inc()调用者获取Foo.class对象的一个​​。 因此,同步规则与使用另一个对象调用实例同步方法而不是静态调用相同。