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

后端 未结 23 1972
北荒
北荒 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 05:05

    I know this is an old question, but with my quick read of the responses here, I didn't really see anyone mention that at times a synchronized method may be the wrong lock.
    From Java Concurrency In Practice (pg. 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;
    }
    

    The above code has the appearance of being thread-safe. However, in reality it is not. In this case the lock is obtained on the instance of the class. However, it is possible for the list to be modified by another thread not using that method. The correct approach would be to use

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

    The above code would block all threads trying to modify list from modifying the list until the synchronized block has completed.

    0 讨论(0)
  • 2020-11-22 05:07

    When java compiler converts your source code to byte code, it handles synchronized methods and synchronized blocks very differently.

    When the JVM executes a synchronized method, the executing thread identifies that the method's method_info structure has the ACC_SYNCHRONIZED flag set, then it automatically acquires the object's lock, calls the method, and releases the lock. If an exception occurs, the thread automatically releases the lock.

    Synchronizing a method block, on the other hand, bypasses the JVM's built-in support for acquiring an object's lock and exception handling and requires that the functionality be explicitly written in byte code. If you read the byte code for a method with a synchronized block, you will see more than a dozen additional operations to manage this functionality.

    This shows calls to generate both a synchronized method and a synchronized block:

    public class SynchronizationExample {
        private int i;
    
        public synchronized int synchronizedMethodGet() {
            return i;
        }
    
        public int synchronizedBlockGet() {
            synchronized( this ) {
                return i;
            }
        }
    }
    

    The synchronizedMethodGet() method generates the following byte code:

    0:  aload_0
    1:  getfield
    2:  nop
    3:  iconst_m1
    4:  ireturn
    

    And here's the byte code from the synchronizedBlockGet() method:

    0:  aload_0
    1:  dup
    2:  astore_1
    3:  monitorenter
    4:  aload_0
    5:  getfield
    6:  nop
    7:  iconst_m1
    8:  aload_1
    9:  monitorexit
    10: ireturn
    11: astore_2
    12: aload_1
    13: monitorexit
    14: aload_2
    15: athrow
    

    One significant difference between synchronized method and block is that, Synchronized block generally reduce scope of lock. As scope of lock is inversely proportional to performance, its always better to lock only critical section of code. One of the best example of using synchronized block is double checked locking in Singleton pattern where instead of locking whole getInstance() method we only lock critical section of code which is used to create Singleton instance. This improves performance drastically because locking is only required one or two times.

    While using synchronized methods, you will need to take extra care if you mix both static synchronized and non-static synchronized methods.

    0 讨论(0)
  • 2020-11-22 05:08

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 05:08

    Synchronizing with threads. 1) NEVER use synchronized(this) in a thread it doesn't work. Synchronizing with (this) uses the current thread as the locking thread object. Since each thread is independent of other threads, there is NO coordination of synchronization. 2) Tests of code show that in Java 1.6 on a Mac the method synchronization does not work. 3) synchronized(lockObj) where lockObj is a common shared object of all threads synchronizing on it will work. 4) ReenterantLock.lock() and .unlock() work. See Java tutorials for this.

    The following code shows these points. It also contains the thread-safe Vector which would be substituted for the ArrayList, to show that many threads adding to a Vector do not lose any information, while the same with an ArrayList can lose information. 0) Current code shows loss of information due to race conditions A) Comment the current labeled A line, and uncomment the A line above it, then run, method loses data but it shouldn't. B) Reverse step A, uncomment B and // end block }. Then run to see results no loss of data C) Comment out B, uncomment C. Run, see synchronizing on (this) loses data, as expected. Don't have time to complete all the variations, hope this helps. If synchronizing on (this), or the method synchronization works, please state what version of Java and OS you tested. Thank you.

    import java.util.*;
    
    /** RaceCondition - Shows that when multiple threads compete for resources 
         thread one may grab the resource expecting to update a particular 
         area but is removed from the CPU before finishing.  Thread one still 
         points to that resource.  Then thread two grabs that resource and 
         completes the update.  Then thread one gets to complete the update, 
         which over writes thread two's work.
         DEMO:  1) Run as is - see missing counts from race condition, Run severa times, values change  
                2) Uncomment "synchronized(countLock){ }" - see counts work
                Synchronized creates a lock on that block of code, no other threads can 
                execute code within a block that another thread has a lock.
            3) Comment ArrayList, unComment Vector - See no loss in collection
                Vectors work like ArrayList, but Vectors are "Thread Safe"
             May use this code as long as attribution to the author remains intact.
         /mf
    */ 
    
    public class RaceCondition {
        private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
    //  private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)
    
        private String countLock="lock";    // Object use for locking the raceCount
        private int raceCount = 0;        // simple add 1 to this counter
        private int MAX = 10000;        // Do this 10,000 times
        private int NUM_THREADS = 100;    // Create 100 threads
    
        public static void main(String [] args) {
        new RaceCondition();
        }
    
        public RaceCondition() {
        ArrayList<Thread> arT = new ArrayList<Thread>();
    
        // Create thread objects, add them to an array list
        for( int i=0; i<NUM_THREADS; i++){
            Thread rt = new RaceThread( ); // i );
            arT.add( rt );
        }
    
        // Start all object at once.
        for( Thread rt : arT ){
            rt.start();
        }
    
        // Wait for all threads to finish before we can print totals created by threads
        for( int i=0; i<NUM_THREADS; i++){
            try { arT.get(i).join(); }
            catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
        }
    
        // All threads finished, print the summary information.
        // (Try to print this informaiton without the join loop above)
        System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
                    MAX*NUM_THREADS, raceList.size(), raceCount );
        System.out.printf("Array lost %,d. Count lost %,d\n",
                 MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
        }   // end RaceCondition constructor
    
    
    
        class RaceThread extends Thread {
        public void run() {
            for ( int i=0; i<MAX; i++){
            try {
                update( i );        
            }    // These  catches show when one thread steps on another's values
            catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
            catch( OutOfMemoryError oome ) { System.out.print("O"); }
            }
        }
    
        // so we don't lose counts, need to synchronize on some object, not primitive
        // Created "countLock" to show how this can work.
        // Comment out the synchronized and ending {, see that we lose counts.
    
    //    public synchronized void update(int i){   // use A
        public void update(int i){                  // remove this when adding A
    //      synchronized(countLock){            // or B
    //      synchronized(this){             // or C
            raceCount = raceCount + 1;
            raceList.add( i );      // use Vector  
    //          }           // end block for B or C
        }   // end update
    
        }   // end RaceThread inner class
    
    
    } // end RaceCondition outter class
    
    0 讨论(0)
  • 2020-11-22 05:11

    Synchronized methods can be checked using reflection API. This can be useful for testing some contracts, such as all methods in model are synchronized.

    The following snippet prints all the synchronized methods of Hashtable:

    for (Method m : Hashtable.class.getMethods()) {
            if (Modifier.isSynchronized(m.getModifiers())) {
                System.out.println(m);
            }
    }
    
    0 讨论(0)
提交回复
热议问题