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

发布于 2024-10-26 12:25:41 字数 594 浏览 3 评论 0原文

我想了解 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 上的锁。

我的问题是这两个调用如何相互同步? 调用静态方法是否也会获取所有实例化的锁,或者相反(这似乎更合理)?


编辑:

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

I want to understand how locking is done on static methods in 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.

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.
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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

橘虞初梦 2024-11-02 12:25:41

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

Static and instance synchronized methods are not related to each other, therefore you need to apply some additional synchronization between them, like this:

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).

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(); }
}
凶凌 2024-11-02 12:25:41

同步静态方法实际上相当于:

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

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

来自 JLS 的第 8.4.3.6 节

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

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.

From section 8.4.3.6 of the JLS:

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.

千柳 2024-11-02 12:25:41

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

它会告诉你:

您可能想知道当
调用静态同步方法,
因为关联了静态方法
与一个类,而不是一个对象。在这个
在这种情况下,线程获取
Class 对象的内在锁
与班级相关联。从而访问
控制类的静态字段
通过与不同的锁
锁定该类的任何实例。

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

If you read 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.

which tells you all you need to know.

朱染 2024-11-02 12:25:41

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

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

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

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".

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

夏天碎花小短裙 2024-11-02 12:25:41

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

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

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

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

Static locks are attached to the class definition and thus is shared between all instances of that class.

Synchronization of none static methods 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.

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

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

染火枫林 2024-11-02 12:25:41

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

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. So the synchronization rules are the same as if instead of static call you called an instance synchronized method with another object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文