简体   繁体   English

“同步功能”与“功能内部的同步块”之间在功能上有什么区别吗?

[英]Is there any functional difference between a 'synchronized function' and a 'synchronized block inside the function'?

Is there any difference between the two : 两者之间有什么区别:

public void synchronized func() {
}

and

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

I understand in the first case the whole function func is synchronized and in the second case only a part of the function's code is synchronized. 我知道在第一种情况下,整个函数func是同步的,而在第二种情况下,仅函数代码的一部分是同步的。 But does it make a difference ? 但这有区别吗? I mean instructions are always executed one after the another. 我的意思是指令总是一个接一个地执行。 It won't be that if a thread is unable to acquire the lock as it reaches the synchronized block, it will start the operations after the synchronized block ! 如果线程到达同步块时无法获取锁,那将不是在同步块之后开始操作!

Is there any functional difference at all or it is just a good practice ? 在功能上有什么不同吗?还是只是一个好习惯?

in the second case only a part of the function's code is synchronized. 在第二种情况下,仅部分功能代码被同步。 But does it make a difference ? 但这有区别吗?

Yes, it does make a difference if there is a lot of code outside of the synchronized part. 是的,如果在同步部分之外有很多代码,这的确会有所作为。

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

You want to keep your critical section as small as possible. 您想使关键部分尽可能小。

It won't be that if a thread is unable to acquire the lock as it reaches the synchronized block, it will start the operations after the synchronized block ! 如果线程到达同步块时无法获取锁,那将不是在同步块之后开始操作!

No, but it will have been able to finish the operation before the synchronized block, and it also does not keep anyone waiting while it is doing the operations after the synchronized block. 否,但是它将能够在同步块之前完成操作,并且在同步块之后执行操作时也不会使任何人等待。

Even if there is no more code outside the synchronized block, the construct is useful, as you can synchronize on other things than this , for example to keep the lock private or more granular . 即使有同步块外没有更多的代码,构建体是有用的,因为你可以在其他事情比同步this ,例如保持锁定私人或更精细

I don't think there's any practical difference in the above. 我认为以上内容没有任何实际差异。

However , I would favour the latter since it's more flexible. 但是 ,我倾向于后者,因为它更灵活。 Instead of locking on the containing object ( this ) you could lock on a particular lock object, and different methods could specify different lock objects (depending on the synchronisation requirements). 除了锁定包含对象( this )之外,您还可以锁定特定的锁定对象,并且不同的方法可以指定不同的锁定对象(取决于同步要求)。 This means you can tune the synchronisation to be more fine-grained as/when you need it. 这意味着您可以在需要时将同步调整为更细粒度。

eg 例如

public synchronized void doSomething() {
   ...
}

(locks on this ) this锁定)

vs.

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

From a locking point of view there is no difference. 从锁定的角度来看,没有区别。

From a byte code point of view, you can tell the first method is synchronized using reflection or most class viewers. 从字节码的角度来看,您可以告诉第一种方法是使用反射或大多数类查看器进行同步的。 The second case is harder to determine it is the case. 第二种情况很难确定是这种情况。

The block synchronization is preferred if you want to hide the lock used, ie you are not using this so a caller cannot confuse things. 如果要隐藏使用的锁(即您不使用this锁),则块同步是首选的,这样调用者就不会感到困惑。

You need to keep Critical Section as small as possible. so synchronized(this) is more useful 您需要使“ Critical Section as small as possible. so synchronized(this) is more useful Critical Section as small as possible. so synchronized(this) is more useful

But if your critical section is your method then there you can go ahead and declare method as synchronized 但是,如果您的关键部分是您的方法,那么您可以继续并将该方法声明为已synchronized

From 1.5 onwards you can always use ReentrantLock 从1.5开始,您可以始终使用ReentrantLock

A Reentrant mutual exclusion Lock with the same basic behaviour and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities. 可重入互斥锁,具有与使用同步方法和语句访问的隐式监视锁相同的基本行为和语义,但具有扩展功能。

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

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

If you're synchronizing the entire contents of the method then there is no functional difference. 如果您要同步方法的全部内容,则不会有功能上的差异。 If you're only synchronizing a part of the method then the scope of the sycnrhonization is different. 如果仅同步方法的一部分,则同步化的范围会有所不同。

You're correct that the code after the synchronized block will not be executed before the synchronized block. 您是正确的,同步块之后的代码将不会在同步块之前执行。 However threads can be swapped out at any point that's not synchronized. 但是,可以在任何不同步的点上换出线程。 Consider the following: 考虑以下:

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

If there are two threads, A & B and A gets the lock B will block until A exits the synchronized block. 如果有两个线程,则A&B和A获取锁B将会阻塞,直到A退出同步块。 However A could be swapped out as soon as it exits this block. 但是,一旦退出该块,就可以将其换出。 B could then enter the synchronized block and complete the function before A gets swapped back in. 然后,B可以进入同步块并完成功能,然后再换回A。

This can be used quite commonly, eg to ensure a mutable instance variable is consistent for the scope of a calculation while allowing multiple threads to perform the expensive calculation. 这可以非常普遍地使用,例如,确保可变实例变量在计算范围内保持一致,同时允许多个线程执行昂贵的计算。 Eg 例如

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

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

Thus, the code: 因此,代码:

synchronized void bump() {
    count++;
}

has exactly the same effect as: 具有与以下功能完全相同的效果:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM