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.get
和Foo.inc()
。 您可以通过共享相同的静态锁或通过相同的实例锁来执行此操作。
这两个调用不会相互同步。 正如你所说, f.get()
的调用者获取f
对象的锁定和Foo.inc()
调用者获取Foo.class
对象的一个。 因此,同步规则与使用另一个对象调用实例同步方法而不是静态调用相同。