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

后端 未结 23 2331
北荒
北荒 2020-11-22 04:29

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

23条回答
  •  清歌不尽
    2020-11-22 04:53

    TLDR; Neither use the synchronized modifier nor the synchronized(this){...} expression but synchronized(myLock){...} where myLock is a final instance field holding a private object.


    The difference between using the synchronized modifier on the method declaration and the synchronized(..){ } expression in the method body are this:

    • The synchronized modifier specified on the method's signature
      1. is visible in the generated JavaDoc,
      2. is programmatically determinable via reflection when testing a method's modifier for Modifier.SYNCHRONIZED,
      3. requires less typing and indention compared to synchronized(this) { .... }, and
      4. (depending on your IDE) is visible in the class outline and code completion,
      5. uses the this object as lock when declared on non-static method or the enclosing class when declared on a static method.
    • The synchronized(...){...} expression allows you
      1. to only synchronize the execution of parts of a method's body,
      2. to be used within a constructor or a (static) initialization block,
      3. to choose the lock object which controls the synchronized access.

    However, using the synchronized modifier or synchronized(...) {...} with this as the lock object (as in synchronized(this) {...}), have the same disadvantage. Both use it's own instance as the lock object to synchronize on. This is dangerous because not only the object itself but any other external object/code that holds a reference to that object can also use it as a synchronization lock with potentially severe side effects (performance degradation and deadlocks).

    Therefore best practice is to neither use the synchronized modifier nor the synchronized(...) expression in conjunction with this as lock object but a lock object private to this object. For example:

    public class MyService {
        private final lock = new Object();
    
        public void doThis() {
           synchronized(lock) {
              // do code that requires synchronous execution
            }
        }
    
        public void doThat() {
           synchronized(lock) {
              // do code that requires synchronous execution
            }
        }
    }
    

    You can also use multiple lock objects but special care needs to be taken to ensure this does not result in deadlocks when used nested.

    public class MyService {
        private final lock1 = new Object();
        private final lock2 = new Object();
    
        public void doThis() {
           synchronized(lock1) {
              synchronized(lock2) {
                  // code here is guaranteed not to be executes at the same time
                  // as the synchronized code in doThat() and doMore().
              }
        }
    
        public void doThat() {
           synchronized(lock1) {
                  // code here is guaranteed not to be executes at the same time
                  // as the synchronized code in doThis().
                  // doMore() may execute concurrently
            }
        }
    
        public void doMore() {
           synchronized(lock2) {
                  // code here is guaranteed not to be executes at the same time
                  // as the synchronized code in doThis().
                  // doThat() may execute concurrently
            }
        }
    }
    

提交回复
热议问题