使用同步方法而不是同步块是否有优点?

有谁能举例说明同步方法优于同步块的优点吗? 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
相关文章
相关标签/搜索