为什么将虚拟对象作为块级同步的参数传递?

发布于 2025-01-01 13:23:47 字数 417 浏览 3 评论 0原文

在 Spring 源代码中找到了这段代码。这是将 XML 文件转换为 Bean Tree 的第一步。

/** Synchronization monitor for the "refresh" and "destroy" */
    private final Object startupShutdownMonitor = new Object();

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();
}

Found this code in the Spring source. This is the first step where the XML file is converted to Bean Tree.

/** Synchronization monitor for the "refresh" and "destroy" */
    private final Object startupShutdownMonitor = new Object();

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();
}

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

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

发布评论

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

评论(6

飘过的浮云 2025-01-08 13:23:47

该习惯用法用于更精细的级别同步。以下是 Java 教程 的摘录。您可以使用synchronized(this),但它会锁定整个对象

同步语句对于提高并发性也很有用
细粒度同步。例如,假设 MsLunch 类有
两个实例字段 c1 和 c2 从不一起使用。全部
这些字段的更新必须同步,但没有理由这样做
防止 c1 的更新与 c2 的更新交错 —
这样做会产生不必要的阻塞,从而减少并发性。
而不是使用同步方法或以其他方式使用锁
与此相关的是,我们创建两个对象只是为了提供锁。

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

从 Java 5 开始,java 引入了 Lock 抽象提供更多功能。因此,您可以执行如下操作,而不是使用synchronized(obj)。了解更多详细信息

Lock lock = new ReentrantLock();

lock.lock();

c1++;

lock.unlock();

This idiom is used for finer level synchronization. Here is the excerpt from the Java tutorial. You could have used synchronized(this) but that whould have locked on the entire object.

Synchronized statements are also useful for improving concurrency with
fine-grained synchronization. Suppose, for example, class MsLunch has
two instance fields, c1 and c2, that are never used together. All
updates of these fields must be synchronized, but there's no reason to
prevent an update of c1 from being interleaved with an update of c2 —
and doing so reduces concurrency by creating unnecessary blocking.
Instead of using synchronized methods or otherwise using the lock
associated with this, we create two objects solely to provide locks.

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

Starting Java 5, java introduced Lock abstraction providing more functionality. So, instead of synchronized(obj) you can do something like below. Read more details here

Lock lock = new ReentrantLock();

lock.lock();

c1++;

lock.unlock();
南城旧梦 2025-01-08 13:23:47

我不能具体代表 Spring 作者,但总的来说......

这样做是为了使代码同步(显然),但故意不在 this 上同步。

我们为什么要这样做?有几个原因:

  1. 该类中还有其他同步块,但这些块与此块之间不存在相互依赖性。因此,它们不应该围绕同一个锁进行同步 - 每个资源都围绕不同的对象进行同步。
  2. 您想要对您班级的用户隐藏该锁。始终存在这样的风险:您的某个用户可能决定执行 synchronized(theObject) 并最终在类外部使用与您在类内部使用的相同对象作为锁。在某些情况下,这可能会导致严重的性能/并发问题

为什么要使用对象?因为这就是获得锁所需要的一切,其他任何东西都会带来更多的开销。

I can't speak for the Spring authors specifically, but in general...

This is done so that the code is synchronized (obviously) but intentionally not synchronized on this.

Why would we want to do this? There are a couple of reasons

  1. There are other synchronized blocks within the class, but there is no inter-dependencies between those blocks and this one. Therefore they should not be synchronized around the same lock - each resource is synchronized around a different object.
  2. You want to hide the lock from the users of your class. There's always a risk that one of your users might decide to do synchronized(theObject) and end up using the same object as a lock outside your class as you used inside your class. In some cases this could cause serious performance/concurrency issues

Why an Object? Because that's all that's needed in order to get a lock, and anything else would introduce more overhead.

全部不再 2025-01-08 13:23:47

我假设您从根本上想知道为什么他们不使用synchronized(this)?您发布的代码可能更好的原因大致有两个。

  1. 安全(或者更确切地说,行为的确定性)。由于其他类可能引用您的类的实例,因此它们也可以自由地对其进行同步。 (事实上​​,每次this上同步时,几乎肯定是在另一个类的监视器上同步)。您可以编写代码,使其独立工作,但如果其他代码使用它以特定方式同步,则会产生死锁。在 this 上同步实际上是公开的,但我怀疑您通常会记录它(或者其他开发人员会阅读该文档)。通过在这样的私有最终字段上进行同步,您可以保证没有其他代码可以在同一对象上进行同步,从而极大地简化了您需要保护的逻辑。
  2. 同一类中的多个操作。例如,如果您有两个单独的计数器,并且正在使用同步来防止丢失更新,那么写入计数器 1 就没有理由阻止读取计数器 2。如果一切都在 this< 上同步/code>,那么这些方法中只能同时发生其中一种。通过对特定对象进行同步,您可以创建组内互斥的方法/块组,但不会阻止其他组中的块继续进行。

第一个可以说是最重要的,因为它可能会设置一个非常难以调试的定时炸弹。第二个也是相关的 - 开发人员经常在没有意识到的情况下过度限制独立的操作 - 但仅适用于同一类中确实有多个操作组的情况。

如今,如果我要同步,我总是会在特定的 new Object() 字段上进行同步,即使目前只是一个操作。

I assume that fundamentally you're wondering why they didn't use synchronized(this)? There are broadly two reasons why the code you've posted might be better.

  1. Safety (or rather, certainty of behaviour). Since other classes might have a reference to an instance of your class, they are also free to synchronize on it too. (In fact, every time you don't synchronize on this you're almost certainly synchronizing on the monitor of another class). You could write your code such that it works standalone, but creates deadlocks if some other code using it, synchronizes in a particular way. Synchronizing on this is effectively public, but I doubt you'd typically document it (or that another developer would read that documentation). By synchronizing on a private final field like this, you can guarantee that no other code can synchronize on the same object, massiovely simplifying the logic of what you need to protect.
  2. Multiple operations within the same class. If you have two separate counters for example and are using synchronization to prevent lost updates - there's no reason why a write to counter 1 should block a read of counter 2. If everything synchronizes on this, then only one of those methods can ever occur at once. Synchronizing on specific objects lets you create groups of methods/blocks that are mutually exclusive within the group, but don't prevent blocks from another group from proceeding.

The first is arguably the most important, as it can set up a ticking time bomb that can be very difficult to debug. The second is also relevant - and developers often over-constraint independent operations like that without realising - but only applies when you do have multiple groups of operations within the same class.

Nowadays if I'm synchronizing, I'll always do it on a specific new Object() field, even if it's just a single operation for the moment.

野味少女 2025-01-08 13:23:47

啊,我以前见过这个:)我实际上也思考过同样的事情。

如果我没记错的话,这是来自 AbstractApplicationContext 。

将一个方法标记为同步意味着没有 2 个线程可以同时调用该方法或任何其他同步方法(锁位于类上)。

拥有一个监视器对象并在同步块中使用它具有相同的效果,但对于使用相同虚拟对象的同步块中的所有代码而言。

如果我没记错的话,在同一个类中还有另一个监视器,称为 activeMonitor。

这允许更高的并发性(线程同时访问两个对象同步的方法)。

这可以让他安全地避免将他的监视器(他的班级之外的任何人都没有兴趣)泄露给其他可能滥用它的对象(将其置于永久权限状态),从而在这个过程中弄乱他的监视器。

Ah I've seen this before :) I've actually pondered the same thing.

This is from AbstractApplicationContext if I remember correctly.

Marking a method as synchronized means that no 2 threads can be calling this method or any other synchronized method at the same time (the lock is on class).

Having a monitor object and using it in a synchronized block like this has the same effect but for all code in synchronized blocks that use the same dummy object.

If I remember correctly as well there is another monitor in this very same class called activeMonitor.

this allows for higher concurrency (threads accessing methods synchronized by both objects at the same time).

this allows keeps him safe from leaking his monitor (which is of no interest to anyone outside his class) out to other objects that might abuse it (place it in a state of eternal dibs), thus messing with his in the process.

染墨丶若流云 2025-01-08 13:23:47

如果一段代码具有某些类变量,并且彼此完全独立,那么与其使用 synchronize(this) 获取整个对象的锁,不如对虚拟对象使用锁。里面的代码仍然受到保护,因为监视器现在处于虚拟对象锁定状态。

If a piece of code having certain class variables is completely independent from the other, then instead of acquiring a lock on the entire object by using synchronize(this) it is better to use lock on dummy object. The code inside is still protected because the monitor now lies with dummy object lock.

子栖 2025-01-08 13:23:47
private final Object startupShutdownMonitor = new Object();

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
       // Prepare this context for refreshing.
       prepareRefresh();
   }

}

这相当于以下内容:

public void refresh() throws BeansException, IllegalStateException {
      //Do something that does not affect the state of the object
      System.out.println("I am inside the refresh method() and will accquire lock on the object now");
      prepareRefresh();
}

private synchronized void preparedRefresh() {
    //Do something thread safe here
    //Since the thread here has the monitor it can safely alter the state of the class instance here with causing inconsistensy
}

获取实例对象 startupShutdownMonitor 的锁与获取调用刷新方法的类的实例的锁相同。

private final Object startupShutdownMonitor = new Object();

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
       // Prepare this context for refreshing.
       prepareRefresh();
   }

}

This is equivalent to the following

public void refresh() throws BeansException, IllegalStateException {
      //Do something that does not affect the state of the object
      System.out.println("I am inside the refresh method() and will accquire lock on the object now");
      prepareRefresh();
}

private synchronized void preparedRefresh() {
    //Do something thread safe here
    //Since the thread here has the monitor it can safely alter the state of the class instance here with causing inconsistensy
}

Acquiring a lock on the instance object startupShutdownMonitor is same as acquiring a lock on the instance of the class on which refresh method is being called upon.

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