繁体   English   中英

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

[英]Concurrency in Java: synchronized static methods

我想了解如何在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是没有意义的,因为它不会做任何需要在实例上进行同步的事情)。

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

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

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对象关联的监视器。 对于实例方法,使用与此关联的监视器(调用该方法的对象)。

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

它会告诉你:

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

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

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

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

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

Static锁附接到class定义并且因此该类的所有实例之间共享。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM