synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊。如果再細的分類,synchronized可作用于instance變量、object reference(對象引用)、static函數和class literals(類名稱字面常量)身上。
注意:
A.無論synchronized關鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數當作鎖――而且同步方法很可能還會被其他線程的對象訪問。
B.每個對象只有一個鎖(lock)與之相關聯。
C.實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。
1.對象實例的鎖
~~~
class Test{
public synchronized void f1(){
//do something here
}
public void f2(){
synchronized(this){
//do something here
}
}
}
~~~
上面的f1()和f2()效果一致, synchronized取得的鎖都是Test某個實列(this)的鎖.比如: Test t = new Test();線程A調用t.f2()時, 線程B無法進入t.f1(),直到t.f2()結束.
作用:多線程中訪問Test的同一個實例的同步方法時會進行同步.
2.class的鎖
~~~
class Test{
final static Object o= new Object();
public static synchronized void f1(){
//do something here
}
public static void f2(){
synchronized(Test.class){
//do something here
}
}
public static void f3(){
try {
synchronized (Class.forName("Test")) {
//do something here
}
}
catch (ClassNotFoundException ex) {
}
}
public static void g(){
synchronized(o){
//do something here
}
}
}
~~~
上面f1(),f2(),f3(),g()效果一致
??f1(),f2(),f3()中synchronized取得的鎖都是Test.class的鎖.
??g()是自己產生一個對象o,利用o的鎖做同步
?? 作用:多線程中訪問此類或此類任一個實例的同步方法時都會同步. singleton模式lazily initializing屬于此類.
3.static method
~~~
class Test{
private static int v = 0;
public static void f1(){
//do something, 但函數中沒用用到v
}
public synchronized static void f2(){
//do something, 函數中對v進行了讀/寫.
}
}
~~~
多線程中使用Test的某個實列時,
?? (1)f1()是線程安全的,不需要同步
?? (2)f2()這個靜態方法中使用了函數外靜態變量,所以需要同步.