两者之间有什么区别:
public void synchronized func() {
}
和
public void func() {
synchronized(this) {
}
}
我理解在第一种情况下整个函数func
是同步的,而在第二种情况下只有部分函数代码是同步的。但这有什么不同吗?我的意思是指令总是一个接一个地执行。并不是说如果一个线程在到达同步块时无法获得锁,它会在同步块之后开始操作!
是否有任何功能差异,或者这只是一个好习惯?
两者之间有什么区别:
public void synchronized func() {
}
和
public void func() {
synchronized(this) {
}
}
我理解在第一种情况下整个函数func
是同步的,而在第二种情况下只有部分函数代码是同步的。但这有什么不同吗?我的意思是指令总是一个接一个地执行。并不是说如果一个线程在到达同步块时无法获得锁,它会在同步块之后开始操作!
是否有任何功能差异,或者这只是一个好习惯?
在第二种情况下,只有部分函数代码是同步的。但这有什么不同吗?
是的,如果在同步部分之外有很多代码,它确实会有所作为。
public void func() {
someHeavyOperations();
synchronized(this) {
criticalSectionOperations();
}
someMoreHeavyOperations();
}
您希望使您的关键部分尽可能小。
不会是如果一个线程在到达同步块时无法获得锁,它会在同步块之后开始操作!
不,但它能够在同步块之前完成操作,并且它在同步块之后执行操作时也不会让任何人等待。
即使在同步块之外没有更多代码,该结构也很有用,因为您可以在除 之外的其他事情上进行同步this
,例如保持锁私有或更细化。
我认为上述内容没有任何实际区别。
但是,我更喜欢后者,因为它更灵活。您可以锁定特定的锁定对象,而不是锁定包含对象 ( this
),并且不同的方法可以指定不同的锁定对象(取决于同步要求)。这意味着您可以在需要时将同步调整为更细粒度。
例如
public synchronized void doSomething() {
...
}
(锁定this
)
对比
public void doSomething() {
synchronized(someLockObject) {
...
}
}
引用 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++; }
}
从锁定的角度来看,没有区别。
从字节码的角度来看,您可以知道第一个方法是使用反射或大多数类查看器进行同步的。第二种情况更难确定是不是这种情况。
如果您想隐藏所使用的锁,则首选块同步,即您没有使用this
,因此调用者不会混淆事物。
你需要保持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()
}
}
}
如果您正在同步该方法的全部内容,则没有功能差异。如果您只是同步方法的一部分,那么同步的范围是不同的。
您是正确的,同步块之后的代码不会在同步块之前执行。然而,线程可以在任何不同步的点被换出。考虑以下:
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.