有谁能举例说明同步方法优于同步块的优点吗? html
能够使用反射API检查同步方法。 这对于测试某些合同可能颇有用,例如模型中的全部方法都已同步 。 java
如下代码段显示了Hashtable的全部同步方法: 安全
for (Method m : Hashtable.class.getMethods()) { if (Modifier.isSynchronized(m.getModifiers())) { System.out.println(m); } }
与线程同步。 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
如前所述,当同步功能仅使用“ this”时,同步块能够将用户定义的变量用做锁定对象。 固然,您能够对应该同步的功能区域进行操做。 可是每一个人都说,同步函数和使用“ this”做为锁定对象的块涵盖了整个函数之间没有区别。 这是不正确的,在两种状况下都会生成字节码。 在使用同步块的状况下,应分配局部变量,该变量保留对“ this”的引用。 结果,咱们的功能会更大一些(若是您只有少数几个功能,则不相关)。 ide
您能够在这里找到有关差别的更详细说明: http : //www.artima.com/insidejvm/ed2/threadsynchP.html 函数
关于使用同步块的重要说明:当心用做锁定对象! oop
上面来自user2277816的代码段说明了这一点,由于对字符串文字的引用用做锁定对象。 意识到字符串文字是在Java中自动插入的,您应该开始看到问题:在文字“锁”上同步的每一段代码都共享相同的锁! 这很容易致使彻底不相关的代码死锁。 测试
您不只须要当心使用String对象。 装箱的基元也是一种危险,由于自动装箱和valueOf方法能够根据值重用相同的对象。 this
有关更多信息,请参见: https : //www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+reused
一般在方法级别使用锁是很不礼貌的。 为何经过锁定整个方法来锁定一段不访问任何共享资源的代码。 因为每一个对象都有一个锁,所以能够建立虚拟对象来实现块级同步。 块级效率更高,由于它不会锁定整个方法。
这里有一些例子
方法级别
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 }
[编辑]
对于Vector
和Hashtable
这样的Collection
,当不使用ArrayList
或HashMap
时,它们将被同步,而且您须要设置sync关键字或调用Collections同步方法:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map List myList = Collections.synchronizedList (myList); // single lock for the entire list