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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5443297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 11:09:38  来源:igfitidea点击:

Concurrency in Java: synchronized static methods

javamultithreadingsynchronized

提问by Amir Rachum

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 fand 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 synchronizedworks, but how does static and non-static methods are synchronized with each other. i.e., I don't want two threads to simultaneously call both f.get()and Foo.inc(), but these methods acquire different locks. My question is how is this preventable and is it prevented in the above code.

我的问题不完全是如何static synchronized工作,而是静态和非静态方法如何相互同步。即,我不希望两个线程同时调用f.get()and Foo.inc(),但这些方法获取不同的锁。我的问题是如何避免这种情况,以及在上面的代码中是否可以防止这种情况发生。

采纳答案by axtavt

Static and instance synchronizedmethods 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 synchronizedon get()doesn't make sense, since it doesn't do anything that requires synchronization on instance).

(尽管在这种情况下,留下synchronizedget()没有任何意义,因为它没有做任何事情需要在实例同步)。

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

回答by Jon Skeet

A synchronized static method is effectively equivalent to:

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

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

In other words, it locks on the Classobject associated with the class declaring the method.

换句话说,它锁定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. For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.

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

回答by bmargulies

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. Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class.

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

which tells you all you need to know.

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

回答by Mat

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. They are not "synchronized".

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

You could use a different pattern (singleton), or make all the methods static.

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

回答by Johan Sj?berg

Staticlocks are attached to the classdefinition and thus is shared between all instances of that class.

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

Synchronization of none staticmethods only apply to the current instance of the class (the lock is on the class instance, e.g., this). In your example you have two different locks with no interrelation.

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

I don't want two threads to simultaneously call both f.get() and Foo.inc(), but these methods acquire different locks. My question is how is this preventable and is it prevented in the above code

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

You mustshare a lock to be able to arbitrate access to both f.getand Foo.inc(). You can do this either by sharing the same static lock or by the same instance lock.

必须共享一个锁才能仲裁对f.get和 的访问Foo.inc()。您可以通过共享相同的静态锁或相同的实例锁来做到这一点。

回答by xappymah

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 fobject and caller of Foo.inc()acquires Foo.classobject's one. So the synchronization rules are the same as if instead of static call you called an instance synchronized method with another object.

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