“同步函数”和“函数内部的同步块”之间是否存在功能差异?

时间:2012-09-14 08:59:37

标签: java multithreading thread-safety synchronized

两者之间有什么区别:

public void synchronized func() {
}

public void func() {
   synchronized(this) {
   }
}

我理解在第一种情况下整个函数func是同步的,在第二种情况下,只有部分函数的代码被同步。但它有所作为吗?我的意思是指令总是一个接一个地执行。如果一个线程在到达synchronized块时无法获取锁定,它将不会是同步块之后的操作!

是否有任何功能差异或者这只是一个好习惯?

6 个答案:

答案 0 :(得分:4)

  

在第二种情况下,只有部分功能代码被同步。但它有所作为吗?

是的,如果同步部分之外有很多代码,它确实会有所作为。

public void func() {
   someHeavyOperations();
   synchronized(this) {
      criticalSectionOperations();
   }
   someMoreHeavyOperations();
}

您希望保持关键部分尽可能小。

  

如果一个线程在到达同步块时无法获取锁定,它就会失败,它将在同步块之后启动操作!

不,但是它可以在同步块之前完成操作,并且在同步块之后执行操作时也不会让任何人等待。

即使同步块之外没有其他代码,该构造也很有用,因为您可以在this以外的其他内容上进行同步,例如keep the lock private or more granular

答案 1 :(得分:2)

我认为上述内容没有任何实际差异。

然而,我更赞成后者,因为它更灵活。您可以锁定特定的锁定对象,而不是锁定包含对象(this),而不同的方法可以指定不同的锁定对象(取决于同步要求)。这意味着您可以将同步调整为在需要时更细粒度。

e.g。

public synchronized void doSomething() {
   ...
}

(锁定this

VS

public void doSomething() {
   synchronized(someLockObject) {
      ...
   }
}

答案 2 :(得分:0)

从锁定的角度来看,没有区别。

从字节代码的角度来看,您可以告诉第一个方法是使用反射或大多数类查看器进行同步的。第二种情况更难确定是这种情况。

如果您想隐藏使用的锁定,则首选阻止同步,即您没有使用this,因此呼叫者不会混淆内容。

答案 3 :(得分:0)

您需要保留Critical Section as small as possible. so synchronized(this) is more useful

但如果您的关键部分是您的方法,那么您可以继续将方法声明为synchronized

从1.5开始,您可以随时使用ReentrantLock

  

可重入互斥锁具有与使用同步方法和语句访问的隐式监视器锁相同的基本行为和语义,但具有扩展功能。

class X {
private final ReentrantLock lock = new ReentrantLock();
// ...

public void m() { 
  lock.lock();  // block until condition holds
  try {
    // ... method body
  } finally {
    lock.unlock()
  }
}
}

答案 4 :(得分:0)

如果您正在同步方法的全部内容,则没有功能差异。如果您只是同步方法的一部分,则sycnrhonization的范围是不同的。

同步块之后的代码将不会在同步块之前执行。但是,线程可以在任何未同步的点交换出来。请考虑以下事项:

synchronized (this) {
    //sycnronized bit
}
// some other code

如果有两个主题,A& B和A得到锁B将阻塞,直到A退出同步块。但是,一旦退出该区块,A就可以被换掉。然后B可以进入同步块并在A交换回来之前完成该功能。

这可以很常用,例如确保可变实例变量与计算范围一致,同时允许多个线程执行昂贵的计算。 E.g。

Object localCopy;
synchronized (this) {
    localCopy = this.instanceVar;
}
// expensive calculation using localCopy which won't change even if instanceVar is changed.

答案 5 :(得分:0)

引用JLS http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.3.6

  

因此,代码:

synchronized void bump() {
    count++;
}
  

具有与以下完全相同的效果:

void bump() {
    synchronized (this) { count++; }
}