1

两者之间有什么区别:

public void synchronized func() {
}

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

我理解在第一种情况下整个函数func是同步的,而在第二种情况下只有部分函数代码是同步的。但这有什么不同吗?我的意思是指令总是一个接一个地执行。并不是说如果一个线程在到达同步块时无法获得锁,它会在同步块之后开始操作!

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

4

6 回答 6

4

在第二种情况下,只有部分函数代码是同步的。但这有什么不同吗?

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

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

您希望使您的关键部分尽可能小。

不会是如果一个线程在到达同步块时无法获得锁,它会在同步块之后开始操作!

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

即使在同步块之外没有更多代码,该结构也很有用,因为您可以在除 之外的其他事情上进行同步this,例如保持锁私有或更细化

于 2012-09-14T09:02:54.160 回答
2

我认为上述内容没有任何实际区别。

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

例如

public synchronized void doSomething() {
   ...
}

(锁定this

对比

public void doSomething() {
   synchronized(someLockObject) {
      ...
   }
}
于 2012-09-14T09:03:17.760 回答
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++; }
}
于 2012-09-14T16:45:42.220 回答
0

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

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

如果您想隐藏所使用的锁,则首选块同步,即您没有使用this,因此调用者不会混淆事物。

于 2012-09-14T09:02:32.023 回答
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()
  }
}
}
于 2012-09-14T09:07:35.360 回答
0

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

您是正确的,同步块之后的代码不会在同步块之前执行。然而,线程可以在任何不同步的点被换出。考虑以下:

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

如果有两个线程,A&B 和 A 拿到锁 B 会阻塞,直到 A 退出同步块。但是,A 可以在退出此块后立即换出。然后 B 可以进入同步块并在 A 被换回之前完成该功能。

这可以非常普遍地使用,例如确保可变实例变量在计算范围内保持一致,同时允许多个线程执行昂贵的计算。例如

Object localCopy;
synchronized (this) {
    localCopy = this.instanceVar;
}
// expensive calculation using localCopy which won't change even if instanceVar is changed.
于 2012-09-14T09:08:17.967 回答