使用同步方法而不是同步塊是否有優點?

有誰能舉例說明同步方法優於同步塊的優點嗎? html


#1樓

能夠使用反射API檢查同步方法。 這對於測試某些合同可能頗有用,例如模型中的全部方法都已同步java

如下代碼段顯示了Hashtable的全部同步方法: 安全

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}

#2樓

與線程同步。 1)永遠不要在線程中使用synced(this),這是行不通的。 與(this)同步使用當前線程做爲鎖定線程對象。 因爲每一個線程都獨立於其餘線程,所以沒有同步協調。 2)代碼測試代表,在Mac上的Java 1.6中,方法同步不起做用。 3)Synchronized(lockObj),其中lockObj是在其上同步的全部線程的公共共享對象。 4)ReenterantLock.lock()和.unlock()工做。 參見Java教程。 多線程

如下代碼顯示了這些要點。 它還包含將替換ArrayList的線程安全Vector,以代表添加到Vector的許多線程不會丟失任何信息,而與ArrayList相同的線程可能會丟失信息。 0)當前代碼顯示因爲競爭條件而致使的信息丟失A)註釋當前標記爲A的行,並取消註釋其上方的A行,而後運行,方法會丟失數據,但不該丟失數據。 B)反向執行步驟A,取消註釋B和//結束}。 而後運行以查看結果,沒有數據丟失C)註釋掉B,取消註釋C。運行,請參見同步(此)丟失數據,這與預期的同樣。 沒有時間來完成全部的變體,但願對您有所幫助。 若是與此同步,或者方法同步可行,請說明您測試的Java和OS版本。 謝謝。 jvm

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

#3樓

如前所述,當同步功能僅使用「 this」時,同步塊能夠將用戶定義的變量用做鎖定對象。 固然,您能夠對應該同步的功能區域進行操做。 可是每一個人都說,同步函數和使用「 this」做爲鎖定對象的塊涵蓋了整個函數之間沒有區別。 這是不正確的,在兩種狀況下都會生成字節碼。 在使用同步塊的狀況下,應分配局部變量,該變量保留對「 this」的引用。 結果,咱們的功能會更大一些(若是您只有少數幾個功能,則不相關)。 ide

您能夠在這裏找到有關差別的更詳細說明: http : //www.artima.com/insidejvm/ed2/threadsynchP.html 函數


#4樓

關於使用同步塊的重要說明:當心用做鎖定對象! oop

上面來自user2277816的代碼段說明了這一點,由於對字符串文字的引用用做鎖定對象。 意識到字符串文字是在Java中自動插入的,您應該開始看到問題:在文字「鎖」上同步的每一段代碼都共享相同的鎖! 這很容易致使徹底不相關的代碼死鎖。 測試

您不只須要當心使用String對象。 裝箱的基元也是一種危險,由於自動裝箱和valueOf方法能夠根據值重用相同的對象。 this

有關更多信息,請參見: https : //www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+reused


#5樓

一般在方法級別使用鎖是很不禮貌的。 爲何經過鎖定整個方法來鎖定一段不訪問任何共享資源的代碼。 因爲每一個對象都有一個鎖,所以能夠建立虛擬對象來實現塊級同步。 塊級效率更高,由於它不會鎖定整個方法。

這裏有一些例子

方法級別

class MethodLevel {

  //shared among threads
SharedResource x, y ;

public void synchronized method1() {
   //multiple threads can't access
}
public void synchronized method2() {
  //multiple threads can't access
}

 public void method3() {
  //not synchronized
  //multiple threads can access
 }
}

塊級

class BlockLevel {
  //shared among threads
  SharedResource x, y ;

  //dummy objects for locking
  Object xLock = new Object();
  Object yLock = new Object();

    public void method1() {
     synchronized(xLock){
    //access x here. thread safe
    }

    //do something here but don't use SharedResource x, y
    // because will not be thread-safe
     synchronized(xLock) {
       synchronized(yLock) {
      //access x,y here. thread safe
      }
     }

     //do something here but don't use SharedResource x, y
     //because will not be thread-safe
    }//end of method1
 }

[編輯]

對於VectorHashtable這樣的Collection ,當不使用ArrayListHashMap時,它們將被同步,而且您須要設置sync關鍵字或調用Collections同步方法:

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
相關文章
相關標籤/搜索