有谁能举例说明同步方法优于同步块的优势吗?
#1楼
可以使用反射API检查同步方法。 这对于测试某些合同可能很有用,例如模型中的所有方法都已同步 。
以下代码段显示了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版本。 谢谢。
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 raceList = new ArrayList(); // simple add(#)
// private Vector raceList = new Vector(); // 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 arT = new ArrayList();
// Create thread objects, add them to an array list
for( int i=0; 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
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
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”的引用。 结果,我们的功能会更大一些(如果您只有少数几个功能,则不相关)。
#4楼
关于使用同步块的重要说明:小心用作锁定对象!
上面来自user2277816的代码段说明了这一点,因为对字符串文字的引用用作锁定对象。 意识到字符串文字是在Java中自动插入的,您应该开始看到问题:在文字“锁”上同步的每一段代码都共享相同的锁! 这很容易导致完全不相关的代码死锁。
您不仅需要小心使用String对象。 装箱的基元也是一种危险,因为自动装箱和valueOf方法可以根据值重用相同的对象。
#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
}
[编辑]
对于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