Java 使用同步方法而不是同步块有优势吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/574240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:23:01  来源:igfitidea点击:

Is there an advantage to use a Synchronized Method instead of a Synchronized Block?

javamultithreadingconcurrencylockingsynchronized

提问by Warrior

Can any one tell me the advantage of synchronized method over synchronized block with an example?

任何人都可以通过示例告诉我同步方法相对于同步块的优势吗?

采纳答案by OscarRyz

Can anyone tell me the advantage of the synchronized method over the synchronized block with an example? Thanks.

谁能通过示例告诉我同步方法相对于同步块的优势?谢谢。

There is not a clear advantage of using synchronized method over the block.

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

Perhaps the only one ( but I wouldn't call it an advantage ) is you don't need to include the object reference this.

也许唯一的(但我不会称其为优势)是您不需要包含对象引用this

Method:

方法:

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

Block:

堵塞:

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

See? No advantage at all.

看?一点优势都没有。

Blocks dohave advantages over methods though, mostly in flexibility because you can use another object as lock whereas syncing the method would lock the entire object.

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

Compare:

相比:

// 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) { 
        ... 
    }
}

Also if the method grows you can still keep the synchronized section separated:

此外,如果方法增长,您仍然可以保持同步部分分开:

 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
}

回答by Paul Tomblin

With synchronized blocks, you can have multiple synchronizers, so that multiple simultaneous but non-conflicting things can go on at the same time.

使用同步块,您可以拥有多个同步器,以便多个同时发生但不冲突的事情可以同时进行。

回答by jcrossley3

The only real difference is that a synchronized block can choose which object it synchronizes on. A synchronized method can only use 'this'(or the corresponding Class instance for a synchronized class method). For example, these are semantically equivalent:

唯一真正的区别是同步块可以选择它同步的对象。同步方法只能使用'this'(或同步类方法的相应类实例)。例如,这些在语义上是等价的:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

The latter is more flexible since it can compete for the associated lock of anyobject, often a member variable. It's also more granular because you could have concurrent code executing before and after the block but still within the method. Of course, you could just as easily use a synchronized method by refactoring the concurrent code into separate non-synchronized methods. Use whichever makes the code more comprehensible.

后者更灵活,因为它可以竞争任何对象的关联锁,通常是成员变量。它也更加细化,因为您可以在块之前和之后执行并发代码,但仍然在方法内。当然,您可以通过将并发代码重构为单独的非同步方法来轻松使用同步方法。使用使代码更易于理解的方法。

回答by Peter Lawrey

Note: staticsynchronized methods and blocks work on the Class object.

注意:静态同步方法和块适用于 Class 对象。

public class MyClass {
   // locks MyClass.class
   public static synchronized void foo() {
// do something
   }

   // similar
   public static void foo() {
      synchronized(MyClass.class) {
// do something
      }
   }
}

回答by cdecker

The main difference is that if you use a synchronized block you may lock on an object other than thiswhich allows to be much more flexible.

主要的区别是,如果使用一个同步块可能会比其他的物体上锁定这个这允许更加灵活。

Assume you have a message queue and multiple message producers and consumers. We don't want producers to interfere with each other, but the consumers should be able to retrieve messages without having to wait for the producers. So we just create an object

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

Object writeLock = new Object();

And from now on every time a producers wants to add a new message we just lock on that:

从现在开始,每次生产者想要添加新消息时,我们都会锁定它:

synchronized(writeLock){
  // do something
}

So consumers may still read, and producers will be locked.

所以消费者仍然可以阅读,而生产者将被锁定。

回答by Clint

Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.

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

In the following code one thread modifying the list will not block waiting for a thread that is modifying the map. If the methods were synchronized on the object then each method would have to wait even though the modifications they are making would not conflict.

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

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;
}

回答by iny

Synchronized Method

同步方法

Pros:

优点:

  • Your IDE can indicate the synchronized methods.
  • The syntax is more compact.
  • Forces to split the synchronized blocks to separate methods.
  • 您的 IDE 可以指示同步方法。
  • 语法更紧凑。
  • 强制将同步块拆分为单独的方法。

Cons:

缺点:

  • Synchronizes to this and so makes it possible to outsiders to synchronize to it too.
  • It is harder to move code outside the synchronized block.
  • 与此同步,因此外部人员也可以与它同步。
  • 将代码移到同步块之外更加困难。

Synchronized block

同步块

Pros:

优点:

  • Allows using a private variable for the lock and so forcing the lock to stay inside the class.
  • Synchronized blocks can be found by searching references to the variable.
  • 允许对锁使用私有变量,从而强制将锁留在类中。
  • 可以通过搜索对变量的引用来找到同步块。

Cons:

缺点:

  • The syntax is more complicated and so makes the code harder to read.
  • 语法更复杂,因此使代码更难阅读。


Personally I prefer using synchronized methods with classes focused only to the thing needing synchronization. Such class should be as small as possible and so it should be easy to review the synchronization. Others shouldn't need to care about synchronization.

就我个人而言,我更喜欢将同步方法与只关注需要同步的东西的类一起使用。这样的类应该尽可能小,因此应该很容易检查同步。其他人应该不需要关心同步。

回答by Alex Miller

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 对象之外,这些基本上是相同的。我认为有时会忽略的同步方法的一个缺点是,在使用“this”引用进行同步时,您将外部对象锁定在同一对象上的可能性保持开放。如果您遇到它,这可能是一个非常微妙的错误。在内部显式对象或其他现有字段上进行同步可以避免此问题,完全封装同步。

回答by kishore

Synchronized method is used for lock all the objects Synchronized block is used to lock specific object

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

回答by sudheer

Synchronized method

同步方法

Synchronized methods have two effects.
First, when one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

同步方法有两个效果。
首先,当一个线程正在为一个对象执行同步方法时,所有其他调用同一个对象的同步方法的线程都会阻塞(挂起执行),直到第一个线程完成对对象的处理。

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

其次,当一个同步方法退出时,它会自动建立一个发生在同一个对象的同步方法的任何后续调用之前的关系。这保证了对象状态的更改对所有线程都是可见的。

Note that constructors cannot be synchronized — using the synchronized keyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.

请注意,构造函数不能同步——在构造函数中使用 synchronized 关键字是一个语法错误。同步构造函数没有意义,因为只有创建对象的线程才能在构造对象时访问它。

Synchronized Statement

同步语句

Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock: Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.

与同步方法不同,同步语句必须指定提供内在锁的对象:大多数情况下,我使用它来同步对列表或映射的访问,但我不想阻止对对象所有方法的访问。

Q: Intrinsic Locks and Synchronization Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

问:内在锁和同步 同步是围绕称为内在锁或监视器锁的内部实体构建的。(API 规范通常将此实体简称为“监视器”。)内在锁在同步的两个方面都发挥作用:强制对对象状态进行独占访问,并建立对可见性至关重要的发生前关系。

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

每个对象都有一个与之关联的内在锁。按照惯例,需要对对象字段进行独占且一致访问的线程必须在访问对象之前获取对象的内在锁,然后在访问完成后释放内在锁。线程在获取锁和释放锁之间被称为拥有内在锁。只要一个线程拥有一个内在锁,其他线程就不能获得相同的锁。另一个线程在尝试获取锁时会阻塞。

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

Cross check different outputs with synchronized method, block and without synchronization.

使用同步方法、块和不同步交叉检查不同的输出。