在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();
}
答案 0 :(得分:7)
这个习惯用于更精细的同步。以下是Java tutorial的摘录。您可以使用 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)。阅读更多details here
Lock lock = new ReentrantLock();
lock.lock();
c1++;
lock.unlock();
答案 1 :(得分:1)
我不能专门为春季作者发言,但总的来说......
这样做是为了使代码同步(显然),但故意不在this
上同步。
我们为什么要这样做?有几个原因
synchronized(theObject)
并最终使用同一个对象作为您班级内部锁定的同一个对象。在某些情况下,这可能会导致严重的性能/并发问题为何选择Object
?因为这就是获得锁定所需的全部内容,而其他任何东西都会带来更多的开销。
答案 2 :(得分:1)
我认为从根本上你会想知道他们为什么不使用synchronized(this)
?您发布的代码可能更好的原因有很多。
this
时,你几乎肯定会在另一个类的监视器上进行同步)。您可以编写代码,使其独立运行,但如果其他代码使用它,则会以特定方式进行同步,从而创建死锁。 this
上的同步实际上是公开的,但我怀疑你通常会记录它(或者另一个开发人员会阅读该文档)。通过在这样的私有final字段上进行同步,可以保证没有其他代码可以在同一个对象上同步,从而大大简化了需要保护的逻辑。this
上同步那么这些方法中只有一种可以同时发生。通过在特定对象上进行同步,您可以创建在组内互斥的方法/块组,但不会阻止来自其他组的块继续进行。第一个可以说是最重要的,因为它可以设置一个非常难以调试的定时炸弹。第二个也是相关的 - 开发人员经常过度约束这样的独立操作而没有意识到 - 但仅适用于同一类中有多组操作的情况。
现在,如果我正在进行同步,我将始终在特定的new Object()
字段上进行,即使它目前只是一个操作。
答案 3 :(得分:0)
啊我以前见过这个:)我实际上在考虑同样的事情。
如果我没记错的话,这是来自AbstractApplicationContext。
将方法标记为已同步意味着没有2个线程可以同时调用此方法或任何其他同步方法(锁定在类上)。
拥有一个监视器对象并在这样的同步块中使用它具有相同的效果,但是对于使用相同虚拟对象的同步块中的所有代码。
如果我没记错的话,在同一个类中有另一个名为activeMonitor的监视器。
这允许更高的并发性(线程访问同时由两个对象同步的方法)。
这样可以防止他将他的显示器(这是他班级以外的任何人都不感兴趣)泄露给可能滥用它的其他物体(将其置于永恒的dib状态),从而弄乱他的过程
答案 4 :(得分:0)
如果一段具有某些类变量的代码完全独立于另一个,那么不是通过使用synchronize(this)
获取整个对象的锁定,而是最好对虚拟对象使用锁定。内部的代码仍然受到保护,因为监视器现在位于虚拟对象锁定。
答案 5 :(得分:-1)
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
的锁定与获取正在调用刷新方法的类实例上的锁定相同。