tifyty

pure Java, what else ?

Kategória archívok: Uncategorized

Synchronized metódus, vagy synchronized blokk?

Nézzünk egy nagyon egyszerű Java osztályt, ami fel van megfelelően készítve arra, hogy több szálon is futtathatják ugyanazt a példányt:

public class SynchronizedClass {
	public synchronized void a() {
	}
	public void b() {
		synchronized (this) {
		}
	}
}

Fordítsuk le, és nézzük meg a b() illetve az a() metódusokból generált kódot, és borzadjunk!

verhasp:java verhasp$ javac SynchronizedClass.java 
verhasp:java verhasp$ javap -v -p SynchronizedClass.class 
Classfile /Users/verhasp/epam/.../src/main/java/SynchronizedClass.class
  Last modified 2012.07.08.; size 406 bytes
  MD5 checksum 46a80e90927a503c1838a55ffb5e154e
  Compiled from "SynchronizedClass.java"
public class SynchronizedClass
  SourceFile: "SynchronizedClass.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:

 ... ezt itt kitöröltem, mert csak zavar ...

{
 ... itt van a default konstruktor leírása, meg kódja, semmi extra, törölve ...

  public synchronized void a();
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=0, locals=1, args_size=1
         0: return        

  public void b();
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0       
         1: dup           
         2: astore_1      
         3: monitorenter  
         4: aload_1       
         5: monitorexit   
         6: goto          14
         9: astore_2      
        10: aload_1       
        11: monitorexit   
        12: aload_2       
        13: athrow        
        14: return        
      Exception table:
         from    to  target type
             4     6     9   any
             9    12     9   any

      StackMapTable: number_of_entries = 2
           frame_type = 255 /* full_frame */
          offset_delta = 9
          locals = [ class SynchronizedClass, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
           frame_type = 250 /* chop */
          offset_delta = 4

}
verhasp:java verhasp$ 

Az a() metódus csak egy return. Nem is várunk mást tőle. Persze a modifier-ek között ott van, hogy synchronized, és ezt a JVM figyelembe is veszi. Ellenben a b() metódus. Na az nem egy matyóhímzés! (Elnézést kérek azoktól, akik szerint a matyóhímzés ronda, és ezzel most megbántottam őket, feltéve, hogy ők meg elnézést kérnek a matyó hímzőktől.)

A b() metódus kódja felhasznál két lokális változót, operátor vermet két mélységben. Van egy exception táblája, és külön gondoskodik arról, hogy ha bármilyen kivétel dobódna a szinkronizált részben, akkor az el legyen kapva, akkor is kilépjen a szinkronizációból a kód, és utána újra legyen dobva a kivétel. Ennél már az is jobb, ha a szinkronizálandó blokkot kiemeljük egy külön metódusba:

	public void b() {
		a();
	}

Aminek a byte kódja:

  public void b();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokevirtual #2                  // Method a:()V
         4: return       

Hát nem egyszerűbb?

Ez jusson eszedbe valahányszor szinkronizált blokkot akarsz írni.