简体   繁体   English

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

[英]Concurrency in Java: synchronized static methods

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. 我的问题不是static synchronized工作方式,而是静态和非静态方法如何相互同步。 ie, I don't want two threads to simultaneously call both f.get() and Foo.inc() , but these methods acquire different locks. 即,我不希望两个线程同时调用f.get()Foo.inc() ,但这些方法获取不同的锁。 My question is how is this preventable and is it prevented in the above code. 我的问题是这是如何可以预防的,并且在上面的代码中是否被阻止了。

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

Beware of deadlocks - since this code aquires multiple locks, it should do it in consistent order, ie 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(); }
}

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关联的Class对象。

From section 8.4.3.6 of the JLS : JLS第8.4.3.6节开始

A synchronized method acquires a monitor (§17.1) before it executes. 同步方法在执行之前获取监视器(第17.1节)。 For a class (static) method, the monitor associated with the Class object for the method's class is used. 对于类(静态)方法,使用与方法类的Class对象关联的监视器。 For an instance method, the monitor associated with this (the object for which the method was invoked) is used. 对于实例方法,使用与此关联的监视器(调用该方法的对象)。

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. 在这种情况下,线程获取与该类关联的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. 因此,对类的静态字段的访问由与该类的任何实例的锁不同的锁控制。

which tells you all you need to know. 它告诉你所有你需要知道的。

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. 换句话说,调用f.get() (锁定f )和Foo.inc() (锁定类Foo )可以并发运行。 They are not "synchronized". 它们不是“同步的”。

You could use a different pattern (singleton), or make all the methods static. 您可以使用不同的模式(单例),或使所有方法都是静态的。

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 , eg, this ). none static方法的同步仅适用于类的当前实例(锁定在类实例上 ,例如, this )。 In your example you have two different locks with no interrelation. 在您的示例中,您有两个不同的锁,没有相互关系。

I don't want two threads to simultaneously call both f.get() and Foo.inc(), but these methods acquire different locks. 我不希望两个线程同时调用f.get()和Foo.inc(),但这些方法获取不同的锁。 My question is how is this preventable and is it prevented in the above code 我的问题是这是如何可以预防的,并且在上面的代码中是否被阻止了

You must share a lock to be able to arbitrate access to both f.get and Foo.inc() . 必须共享一个锁才能仲裁对f.getFoo.inc() You can do this either by sharing the same static lock or by the same instance lock. 您可以通过共享相同的静态锁或通过相同的实例锁来执行此操作。

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. 正如你所说, f.get()的调用者获取f对象的锁定和Foo.inc()调用者获取Foo.class对象的一个​​。 So the synchronization rules are the same as if instead of static call you called an instance synchronized method with another object. 因此,同步规则与使用另一个对象调用实例同步方法而不是静态调用相同。

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

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