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


当前回答

我想这个问题是关于线程安全单例和带有双重检查锁定的惰性初始化之间的区别。当我需要实现某些特定的单例时,我总是会参考这篇文章。

这是一个线程安全单例:

// Java program to create Thread Safe 
// Singleton class 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

 //synchronized method to control simultaneous access 
  synchronized public static GFG getInstance()  
  { 
    if (instance == null)  
    { 
      // if instance is null, initialize 
      instance = new GFG(); 
    } 
    return instance; 
  } 
} 

优点: 延迟初始化是可能的。 它是线程安全的。 缺点: getInstance()方法是同步的,因此它会导致性能变慢,因为多个线程不能同时访问它。

这是一个带有双重检查锁定的Lazy初始化:

// Java code to explain double check locking 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

  public static GFG getInstance() 
  { 
    if (instance == null)  
    { 
      //synchronized block to remove overhead 
      synchronized (GFG.class) 
      { 
        if(instance==null) 
        { 
          // if instance is null, initialize 
          instance = new GFG(); 
        } 

      } 
    } 
    return instance; 
  } 
} 

优点: 延迟初始化是可能的。 它也是线程安全的。 克服了synchronized关键字导致的性能下降。 缺点: 第一次,它会影响性能。 由于双止回锁方法的缺点是可以承受的,所以可以 用于高性能多线程应用程序。

详情请参考这篇文章:

https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/

其他回答

In general these are mostly the same other than being explicit about the object's monitor that's being used vs the implicit this object. One downside of synchronized methods that I think is sometimes overlooked is that in using the "this" reference to synchronize on you are leaving open the possibility of external objects locking on the same object. That can be a very subtle bug if you run into it. Synchronizing on an internal explicit Object or other existing field can avoid this issue, completely encapsulating the synchronization.

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

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

也许唯一的一点(但我不认为这是优点)是您不需要包含对象引用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
}

主要的区别是,如果你使用同步块,你可以锁定一个对象,而不是这个,这允许更灵活。

假设您有一个消息队列和多个消息生产者和消费者。我们不希望生产者相互干扰,但是消费者应该能够检索消息,而不必等待生产者。 我们只需要创建一个对象

Object writeLock = new Object();

从现在开始,每当制作人想要添加一条新信息时,我们就会锁定它:

synchronized(writeLock){
  // do something
}

因此,消费者可能仍会阅读,而生产者将被锁定。

来自Java规范摘要: http://www.cs.cornell.edu/andru/javaspec/17.doc.html

The synchronized statement (§14.17) computes a reference to an object; it then attempts to perform a lock action on that object and does not proceed further until the lock action has successfully completed. ... A synchronized method (§8.4.3.5) automatically performs a lock action when it is invoked; its body is not executed until the lock action has successfully completed. If the method is an instance method, it locks the lock associated with the instance for which it was invoked (that is, the object that will be known as this during execution of the body of the method). If the method is static, it locks the lock associated with the Class object that represents the class in which the method is defined. ...

基于这些描述,我想说以前的大多数答案都是正确的,同步方法可能对静态方法特别有用,否则您必须弄清楚如何获得“表示定义方法的类的Class对象”。

编辑:我原本以为这些是对实际Java规范的引用。澄清一下,本页只是对规范的总结/解释

大多数情况下,我使用它来同步对列表或映射的访问,但我不想阻止对对象的所有方法的访问。

在下面的代码中,修改列表的线程不会阻塞等待正在修改映射的线程。如果方法在对象上是同步的,那么每个方法都必须等待,即使它们所做的修改不会冲突。

private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();

public void put( String s, Bar b ) {
  synchronized( myMap ) {
    myMap.put( s,b );
    // then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public void hasKey( String s, ) {
  synchronized( myMap ) {
    myMap.hasKey( s );
  }
}

public void add( Foo f ) {
  synchronized( myList ) {
    myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public Thing getMedianFoo() {
  Foo med = null;
  synchronized( myList ) {
    Collections.sort(myList);
    med = myList.get(myList.size()/2); 
  }
  return med;
}