有人能告诉我同步方法比同步块的优势与一个例子吗?


当前回答

谁能告诉我同步方法比同步块的优势与一个例子?谢谢。

与块相比,使用同步方法并没有明显的优势。

也许唯一的一点(但我不认为这是优点)是您不需要包含对象引用this。

方法:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

布洛克:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

看到了吗?一点好处都没有。

块确实比方法有优势,主要是灵活性,因为你可以使用另一个对象作为锁,而同步方法将锁定整个对象。

比较:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

另外,如果方法增长了,你仍然可以保持同步段的分离:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}

其他回答

Synchronized方法用于锁定所有对象 同步块用于锁定特定对象

关于使用同步块的重要提示:小心你使用的锁对象!

上面user2277816的代码片段说明了这一点,将字符串字面值的引用用作锁定对象。 意识到字符串字面值在Java中是自动互缩的,您应该开始看到问题所在:在字面值“锁”上同步的每段代码都共享同一个锁!这很容易导致完全不相关的代码段发生死锁。

您需要注意的不仅仅是String对象。装箱的原语也是一种危险,因为autoboxing和valueOf方法可以重用相同的对象,这取决于值。

有关更多信息,请参阅: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

我知道这是一个老问题,但通过快速阅读这里的回答,我并没有看到任何人提到同步方法有时可能是错误的锁。 摘自Java并发实践(第72页):

public class ListHelper<E> {
  public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...

public syncrhonized boolean putIfAbsent(E x) {
 boolean absent = !list.contains(x);
if(absent) {
 list.add(x);
}
return absent;
}

上面的代码看起来是线程安全的。然而,现实并非如此。在这种情况下,锁在类的实例上获得。但是,该列表可能被另一个不使用该方法的线程修改。正确的方法是使用

public boolean putIfAbsent(E x) {
 synchronized(list) {
  boolean absent = !list.contains(x);
  if(absent) {
    list.add(x);
  }
  return absent;
}
}

上面的代码将阻止所有试图修改list的线程修改列表,直到同步块完成。

在实际应用中,同步方法相对于同步块的优势在于它们更能抵抗白痴;因为您不能选择任意对象来锁定,所以您不能滥用synchronized方法语法来做一些愚蠢的事情,比如锁定字符串文字或锁定从线程下面更改的可变字段的内容。

另一方面,使用同步方法,您无法保护锁不被任何可以获得对象引用的线程获取。

因此,在方法上使用synchronized作为修饰符可以更好地保护你的奶牛免受伤害,而将synchronized块与私有final锁对象结合使用则可以更好地保护你自己的代码免受奶牛的伤害。

谁能告诉我同步方法比同步块的优势与一个例子?谢谢。

与块相比,使用同步方法并没有明显的优势。

也许唯一的一点(但我不认为这是优点)是您不需要包含对象引用this。

方法:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

布洛克:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

看到了吗?一点好处都没有。

块确实比方法有优势,主要是灵活性,因为你可以使用另一个对象作为锁,而同步方法将锁定整个对象。

比较:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

另外,如果方法增长了,你仍然可以保持同步段的分离:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}