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

时间:2011-03-26 15:28:14

标签: java multithreading synchronized

我想了解如何在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(),但这些方法获取不同的锁。我的问题是这是如何可以预防的,并且在上面的代码中被阻止了。

6 个答案:

答案 0 :(得分:9)

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

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

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

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

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

答案 1 :(得分:8)

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

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

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

来自section 8.4.3.6 of the JLS

  

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

答案 2 :(得分:3)

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

会告诉你:

  

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

告诉你所有你需要知道的事情。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:1)

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

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

  

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

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

答案 5 :(得分:0)

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

相关问题